From bf7816ab7c9dfd08e5708efae30f5839d91b7b27 Mon Sep 17 00:00:00 2001 From: StepanovPlaton Date: Sun, 11 Oct 2026 23:25:22 +0400 Subject: [PATCH] Rename project to SSAU Generator and restructure content - Move projects into content//{docx,pptx} with shared assets/ - Flatten config paths; output = project name in project folder - Add pptx --init scaffold; remove docx exe build - Add feature-complete content/example; ignore content/* except example - Rewrite README and AGENTS.md --- .gitignore | 16 +- AGENTS.md | 111 + README.md | 136 +- .../example}/assets/content-bg.jpg | Bin .../example}/assets/final-bg.jpeg | Bin content/example/assets/images/chart.png | Bin 0 -> 4249 bytes content/example/assets/images/diagram.png | Bin 0 -> 3899 bytes content/example/assets/images/flow.puml | 18 + content/example/assets/images/scheme.png | Bin 0 -> 3900 bytes .../example}/assets/title-bg.jpeg | Bin content/example/assets/title-page.docx | Bin 0 -> 31256 bytes content/example/docx/01-introduction.md | 24 + content/example/docx/02-features.md | 104 + content/example/docx/03-tables.md | 18 + content/example/docx/04-conclusion.md | 14 + content/example/docx/05-bibliography.md | 4 + content/example/docx/06-appendix-a.md | 17 + content/example/docx/config.yaml | 47 + content/example/pptx/config.yaml | 51 + content/example/pptx/slides/00-title.md | 3 + content/example/pptx/slides/01-text.md | 5 + content/example/pptx/slides/02-lists.md | 6 + content/example/pptx/slides/03-table.md | 10 + content/example/pptx/slides/04-image.md | 5 + content/example/pptx/slides/05-puml.md | 5 + content/example/pptx/slides/06-metrics.md | 8 + content/example/pptx/slides/07-flow.md | 5 + content/example/pptx/slides/08-chart.md | 9 + content/example/pptx/slides/09-columns.md | 12 + content/example/pptx/slides/10-notes.md | 7 + content/example/pptx/slides/11-section.md | 3 + content/example/pptx/slides/12-final.md | 3 + docx/AGENTS.md | 302 ++- docx/README.md | 43 +- docx/config.yaml | 145 -- docx/content/01-introduction.md | 41 - docx/content/02-method.md | 154 -- docx/content/03-spheres.md | 105 - docx/content/04-conclusion.md | 37 - docx/content/05-bibliography.md | 7 - docx/content/06-appendix-a.md | 17 - .../content/assets/images/product-funnel.puml | 19 - docx/content/assets/images/scrum-cycle.puml | 26 - docx/content/assets/title-page.docx | Bin 6436 -> 0 bytes docx/package-lock.json | 1982 +---------------- docx/package.json | 19 +- docx/src/cli.js | 14 +- docx/src/config/defaults.js | 19 +- docx/src/config/template.js | 99 +- docx/src/config/validate.js | 3 + docx/src/render/document.js | 9 +- docx/src/render/primitives.js | 27 +- docx/src/render/styles.js | 1 + pptx/AGENTS.md | 127 +- pptx/config.yaml | 130 -- pptx/content/assets/scrum-cycle.puml | 24 - pptx/content/slides/00-title.md | 13 - pptx/content/slides/01-agenda.md | 12 - pptx/content/slides/01-task.md | 19 - pptx/content/slides/02-why-scrum.md | 18 - pptx/content/slides/03-roles.md | 21 - pptx/content/slides/04-events.md | 18 - pptx/content/slides/05-launch.md | 18 - pptx/content/slides/06-spheres.md | 7 - pptx/content/slides/07a-spheres-1-2.md | 21 - pptx/content/slides/07b-spheres-3-4.md | 21 - pptx/content/slides/07c-spheres-5-6.md | 21 - pptx/content/slides/07d-spheres-7-8.md | 21 - pptx/content/slides/07e-spheres-9-10.md | 21 - pptx/content/slides/10-conclusion.md | 17 - pptx/content/slides/11-final.md | 9 - pptx/content/slides/12-scrum-cycle.md | 17 - pptx/package-lock.json | 6 +- pptx/package.json | 6 +- pptx/src/cli.js | 30 +- pptx/src/config.js | 8 +- pptx/src/plantuml.js | 2 +- pptx/src/png.js | 68 + pptx/src/scaffold.js | 115 + video-script.md | 98 - 80 files changed, 1166 insertions(+), 3432 deletions(-) create mode 100644 AGENTS.md rename {pptx/content => content/example}/assets/content-bg.jpg (100%) rename {pptx/content => content/example}/assets/final-bg.jpeg (100%) create mode 100644 content/example/assets/images/chart.png create mode 100644 content/example/assets/images/diagram.png create mode 100644 content/example/assets/images/flow.puml create mode 100644 content/example/assets/images/scheme.png rename {pptx/content => content/example}/assets/title-bg.jpeg (100%) create mode 100644 content/example/assets/title-page.docx create mode 100644 content/example/docx/01-introduction.md create mode 100644 content/example/docx/02-features.md create mode 100644 content/example/docx/03-tables.md create mode 100644 content/example/docx/04-conclusion.md create mode 100644 content/example/docx/05-bibliography.md create mode 100644 content/example/docx/06-appendix-a.md create mode 100644 content/example/docx/config.yaml create mode 100644 content/example/pptx/config.yaml create mode 100644 content/example/pptx/slides/00-title.md create mode 100644 content/example/pptx/slides/01-text.md create mode 100644 content/example/pptx/slides/02-lists.md create mode 100644 content/example/pptx/slides/03-table.md create mode 100644 content/example/pptx/slides/04-image.md create mode 100644 content/example/pptx/slides/05-puml.md create mode 100644 content/example/pptx/slides/06-metrics.md create mode 100644 content/example/pptx/slides/07-flow.md create mode 100644 content/example/pptx/slides/08-chart.md create mode 100644 content/example/pptx/slides/09-columns.md create mode 100644 content/example/pptx/slides/10-notes.md create mode 100644 content/example/pptx/slides/11-section.md create mode 100644 content/example/pptx/slides/12-final.md delete mode 100644 docx/config.yaml delete mode 100644 docx/content/01-introduction.md delete mode 100644 docx/content/02-method.md delete mode 100644 docx/content/03-spheres.md delete mode 100644 docx/content/04-conclusion.md delete mode 100644 docx/content/05-bibliography.md delete mode 100644 docx/content/06-appendix-a.md delete mode 100644 docx/content/assets/images/product-funnel.puml delete mode 100644 docx/content/assets/images/scrum-cycle.puml delete mode 100644 docx/content/assets/title-page.docx delete mode 100644 pptx/config.yaml delete mode 100644 pptx/content/assets/scrum-cycle.puml delete mode 100644 pptx/content/slides/00-title.md delete mode 100644 pptx/content/slides/01-agenda.md delete mode 100644 pptx/content/slides/01-task.md delete mode 100644 pptx/content/slides/02-why-scrum.md delete mode 100644 pptx/content/slides/03-roles.md delete mode 100644 pptx/content/slides/04-events.md delete mode 100644 pptx/content/slides/05-launch.md delete mode 100644 pptx/content/slides/06-spheres.md delete mode 100644 pptx/content/slides/07a-spheres-1-2.md delete mode 100644 pptx/content/slides/07b-spheres-3-4.md delete mode 100644 pptx/content/slides/07c-spheres-5-6.md delete mode 100644 pptx/content/slides/07d-spheres-7-8.md delete mode 100644 pptx/content/slides/07e-spheres-9-10.md delete mode 100644 pptx/content/slides/10-conclusion.md delete mode 100644 pptx/content/slides/11-final.md delete mode 100644 pptx/content/slides/12-scrum-cycle.md create mode 100644 pptx/src/png.js create mode 100644 pptx/src/scaffold.js delete mode 100644 video-script.md diff --git a/.gitignore b/.gitignore index 582c65b..0e3bead 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,18 @@ node_modules/ -report.docx -presentation.pptx -DocxGenerator.exe *.log *.pdf .plantuml-cache/ tools/plantuml.jar + +# Сгенерированные документы и презентации +report.docx +presentation.pptx + +# Пользовательские проекты в content/; в репозитории хранится только пример +content/* +!content/example/ +!content/example/** + +# Сгенерированные файлы примера тоже не коммитим +content/example/*.docx +content/example/*.pptx diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..dba63bd --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,111 @@ +# AGENTS.md — управление проектом SSAU Generator + +Репозиторий содержит два независимых генератора отчётных документов из Markdown. +Этот файл описывает управление проектом в целом. Правила работы с конкретным +документом — в [`docx/AGENTS.md`](docx/AGENTS.md) и [`pptx/AGENTS.md`](pptx/AGENTS.md). + +## Что использовать по запросу пользователя + +- Просит **сгенерировать документ** (отчёт, DOCX, пояснительную записку, + лабораторную работу) — используйте генератор в папке `docx/`. +- Просит **сгенерировать презентацию** (PPTX, слайды) — используйте генератор в + папке `pptx/`. + +Команды запускаются из корня репозитория; генератору указывается `config.yaml` +нужного проекта. Содержимое документа задаётся Markdown-файлами и `config.yaml` +проекта, а не кодом генератора. + +## Правила работы над проектом + +- **Уточните название проекта.** Если пользователь не указал, над каким проектом + ведётся работа, сначала спросите его. Проект — это папка `content/<проект>/`. +- **Один проект за сессию.** В рамках одной сессии работайте только над одним + проектом. +- **Создание — только через `--init`.** Новый проект создавайте командами с флагом + `--init` (см. ниже): они формируют правильную структуру и общий каталог + ресурсов. +- **Имя результата = имя проекта.** Документ и презентация собираются в папку + проекта, а имя файла совпадает с именем проекта: + `content/<проект>/<проект>.docx` и `content/<проект>/<проект>.pptx`. + Соответствующий путь задаётся ключом `output` в `config.yaml`. +- **Пересобирайте после правок.** При любом изменении исходных файлов + (`config.yaml`, `*.md`, ресурсов в `assets/`) заново запускайте сборку docx + и/или pptx, чтобы результат соответствовал исходникам. + +## Структура репозитория + +``` +ssau-generator/ +├── docx/ # генератор DOCX (только код) +├── pptx/ # генератор PPTX (только код) +├── tools/ # общий plantuml.jar (не в git) +├── content/ # проекты (в git хранится только example) +│ └── example/ +│ ├── assets/ # общие ресурсы проекта (для docx и pptx) +│ ├── docx/ # config.yaml + *.md +│ └── pptx/ # config.yaml + slides/ +├── AGENTS.md # этот файл +└── README.md +``` + +## Проекты и каталог content + +- **Один проект = одна папка** `content/<проект>/`. +- Внутри проекта при необходимости лежат папки `docx/` и `pptx/`. +- **Общие ресурсы проекта** (титульный лист, задники, изображения, исходники + `.puml`) размещаются в `content/<проект>/assets/` и используются обоими + генераторами. В `docx/` и `pptx/` внутри проекта хранятся только `config.yaml` + и Markdown. +- Папки `content/*` добавлены в `.gitignore`; в репозитории хранится только + `content/example/`. Рабочие проекты пользователя коммитить не нужно. + +## Создание нового проекта + +Проект создаётся командами с флагом `--init` — они формируют структуру и общие +ресурсы автоматически: + +```powershell +# только документ DOCX +node docx/src/cli.js --content content/<проект>/docx --init + +# только презентация PPTX +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --init + +# оба генератора (каталог content/<проект>/assets/ создаётся первым вызовом +# и переиспользуется вторым) +``` + +После создания отредактируйте `config.yaml` и Markdown; общие ресурсы +(титульный лист, задники, изображения, `.puml`) положите в +`content/<проект>/assets/`. + +## Сборка + +```powershell +# Документ DOCX +node docx/src/cli.js --content content/<проект>/docx --check +node docx/src/cli.js --content content/<проект>/docx + +# Презентация PPTX +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --check +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml +``` + +Результат: `content/<проект>/<проект>.docx` или +`content/<проект>/<проект>.pptx` (имя и путь задаются ключом `output` в +`config.yaml`). После правок исходников пересобирайте файлы. + +## Требования + +- Node.js 18+, зависимости устанавливаются командой `npm install` в `docx/` и + `pptx/`. +- Java 11+ и файл `tools/plantuml.jar` (не хранится в git) — для рендеринга схем + PlantUML (`.puml`). + +## Правила + +- Для сборки документа не редактируйте код генераторов — меняйте `config.yaml` + и Markdown проекта. +- Не коммитьте содержимое `content/`, кроме `content/example/`. +- Не храните ресурсы внутри `docx/` и `pptx/` — общие файлы живут в + `content/<проект>/assets/`. diff --git a/README.md b/README.md index a056c3c..740b380 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,125 @@ -# lab_gen — генераторы отчётных документов +# 📄 SSAU Generator -Монорепозиторий из двух независимых Node.js-генераторов, которые собирают -отчётные документы из обычного Markdown по заданному шаблону/стандарту. +> **SSAU Generator** — это два независимых генератора отчётных документов из обычного **Markdown**: **DOCX**-отчёт по СТО 02068410-004-2018 и **PPTX**-презентация по шаблону Самарского университета. +> +> Главное — это **модульность** и **воспроизводимая сборка**: содержимое задаётся Markdown и `config.yaml`, а не правками кода. + +--- + +## 📦 Состав + +- **`docx/`** — генератор документов **DOCX** по дизайну СТО 02068410-004-2018 + - Титульный лист, оглавление, таблицы, рисунки (включая PlantUML), формулы, список источников и приложения +- **`pptx/`** — генератор презентаций **PPTX** по фирменному шаблону Самарского университета + - 16:9, синий фон, задники, логотип и фирменный шрифт заданы в `config.yaml` +- **`tools/plantuml.jar`** — общий рендерер схем PlantUML (не хранится в git) +- **`content/`** — проекты пользователя: `content/<проект>/{docx,pptx}` и общие ресурсы `content/<проект>/assets/` + +--- + +## 🚀 Возможности + +### 📄 Документ DOCX + +- Сборка из **обычного Markdown** по фиксированному дизайну СТО 02068410-004-2018 +- Готовый **титульный лист** (отдельный `.docx`) и **оглавление** (поле Word) +- Автоматическая **нумерация** разделов, рисунков, таблиц, формул и приложений +- **Таблицы** — обычные и с подписью и автономером +- **Рисунки** — готовые PNG и схемы **PlantUML**, рендеримые автоматически +- **Формулы** с пояснениями и нумерацией +- **Ссылки на источники** и перекрёстные ссылки на номера объектов +- Примечания, определения, приложения с буквенной нумерацией + +### 📽️ Презентация PPTX + +- Сборка из **Markdown**, по одному файлу на слайд +- Четыре типа слайдов: **титульный, разделитель, контент, финальный** — каждый со своим фоном +- **Богатая inline-разметка**: полужирный, курсив, акцент, моноширинный +- **Таблицы, изображения и PlantUML**, схемы-цепочки, карточки-метрики, плашки-выводы +- **Диаграммы** (bar, line, pie, doughnut, area, radar, scatter) из GFM-таблиц +- **Заметки докладчика** как сценарий выступления +- Двухколоночная вёрстка через параметр `side=left|right` + +--- + +## 📂 Структура ``` -lab_gen/ -├── docx/ # генератор DOCX по СТО 02068410-004-2018 (отчёт) -├── pptx/ # генератор PPTX по шаблону Самарского университета (презентация) -└── tools/ # общие внешние инструменты (plantuml.jar) +ssau-generator/ +├── docx/ # генератор DOCX (только код) +├── pptx/ # генератор PPTX (только код) +├── tools/ # общий plantuml.jar (не в git) +├── content/ # проекты (в git хранится только example) +│ └── example/ +│ ├── assets/ # общие ресурсы проекта (для docx и pptx) +│ ├── docx/ # config.yaml + *.md +│ └── pptx/ # config.yaml + slides/ +├── AGENTS.md # инструкции по управлению проектом +└── README.md ``` -## docx/ — DocxGenerator +> Каждый проект — отдельная папка `content/<проект>/`. Готовый пример со всеми возможностями — [`content/example/`](content/example/). -Автономный генератор отчётов **DOCX** из Markdown по дизайну -СТО 02068410-004-2018. Поддерживает титульный лист, оглавление, таблицы, рисунки -(включая PlantUML), формулы, список источников и приложения. +--- + +## 🛠 Требования + +- **Node.js 18+** и зависимости, устанавливаемые командой `npm install` в `docx/` и `pptx/` +- **Java 11+** и файл `tools/plantuml.jar` — для рендеринга схем PlantUML (`.puml`) + +--- + +## 📝 Быстрый старт ```powershell -cd docx -npm install -npm run check # проверка конфига и ссылок -npm run generate # собрать report.docx +npm install --prefix docx +npm install --prefix pptx + +# Документ DOCX +node docx/src/cli.js --content content/example/docx + +# Презентация PPTX +node pptx/src/cli.js -c content/example/pptx/config.yaml ``` -Полная документация — [docx/AGENTS.md](docx/AGENTS.md). +Готовый пример со всеми возможностями — [`content/example/`](content/example/). -## pptx/ — lab-gen-pptx +--- -Генератор презентаций **PPTX** из Markdown по фирменному шаблону Самарского -университета (16:9, синий фон, логотип, фирменный шрифт). Задники и правила -оформления извлечены из `presentation_16.pptx` и заданы в `config.yaml`. +## 🎯 Использование + +### Новый проект + +Проект создаётся командами с флагом `--init` — они формируют структуру и общий каталог ресурсов `content/<проект>/assets/`: ```powershell -cd pptx -npm install -npm run check # проверка конфига и ссылок -npm run generate # собрать presentation.pptx +# только документ DOCX +node docx/src/cli.js --content content/<проект>/docx --init + +# только презентация PPTX +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --init ``` -Формат слайдов, схема конфига и CLI описаны в [pptx/AGENTS.md](pptx/AGENTS.md). +### Сборка -## Требования +```powershell +# Документ DOCX +node docx/src/cli.js --content content/<проект>/docx --check +node docx/src/cli.js --content content/<проект>/docx -- Node.js 18+ (для локальной сборки). -- Java 11+ и `tools/plantuml.jar` — для рендеринга схем PlantUML (`.puml`) - в обоих генераторах. Путь задаётся ключом `plantuml.jar` в `config.yaml`. +# Презентация PPTX +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --check +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml +``` + +Результат собирается в папку проекта и называется по имени проекта: `content/<проект>/<проект>.docx` и `content/<проект>/<проект>.pptx`. + +--- + +## 📚 Документация + +- Управление проектом: [AGENTS.md](AGENTS.md) +- Формат DOCX-документа: [docx/AGENTS.md](docx/AGENTS.md) +- Формат PPTX-презентации: [pptx/AGENTS.md](pptx/AGENTS.md) + +> 💡 **Важно:** Документ и презентация используют общий каталог ресурсов `content/<проект>/assets/`, поэтому титульный лист, задники и изображения переиспользуются обоими генераторами. diff --git a/pptx/content/assets/content-bg.jpg b/content/example/assets/content-bg.jpg similarity index 100% rename from pptx/content/assets/content-bg.jpg rename to content/example/assets/content-bg.jpg diff --git a/pptx/content/assets/final-bg.jpeg b/content/example/assets/final-bg.jpeg similarity index 100% rename from pptx/content/assets/final-bg.jpeg rename to content/example/assets/final-bg.jpeg diff --git a/content/example/assets/images/chart.png b/content/example/assets/images/chart.png new file mode 100644 index 0000000000000000000000000000000000000000..b4089f860f73773bf7384872904c1c4d12cc668d GIT binary patch literal 4249 zcmd^DZD?C%6n<-JUH5_Q5{ycrqR_1fl@Y{maKs-D_UB9SLdIu|Iyic=-yyp6g1j zzL{~Id4z3w!=^N`r&6&eSU|FR_>HA|M;rKU$N`V(MmALpH)2x-thRvVz&6d^0IR1I zryKv5MLcn%;k)c#|I8n2!!*T(%@)=tAcMeEXNoBuv|bzyI+)>smO~DF(^#TA?g;{6 z)P=GT7e<%9NpElQ@D&@8EGZ`~dp~M7mFC?HdxbI0s+g*c&#qI{E++yO< z+|*hl?XI-DA~II1uoPXpLyrqf%V1!|0-(nPJsvD@gMDR81uVpc!Yn5UH)n;t5SSwi z=3;1$OrZhA2GJ7_!zKo-;v>?@qiyzx9FcQ}fdFoER&JG4l%q(pq7OVEgeVxA-6ArS z;e-gDh%1xev4m04XA!m&+zR8E9n5S>9Eh_D3q-4B5LeJ&O|>GMHoICLsuXfoD;2Fm z-(XYXKuM~wcf^!^(^LOKlw`XLLLTnDIyDB0{yQvn&5Y;!W#6wMczJhjK0NC`*X*0- z=^?qXl~XP#B8UMf*{mx+kHgGKUBlaE#+})l1Lqvd7jtLxogEAPvi%hT^oGF5NrlHA zWc%ej!VMO%#z2Dyp7no>c59uf*obQY;V%AE(QD6JvX3IA!`_e{ICCMSh1UCDG0h@Y zl*hJbRL!iz$qDQU8&y*Qd!0;3tmRAC-9)N@N?peYZFXPUzdFOio!LHo9x{WrP$Swu zb+&qb`v}5+-s&;@vRJwclVd{;y-R$+)O_wfz7Uj__4+5`W8M&=U^58PC}j953}XHR zDstvHPLh)GL#J+Gvxm<+m%9Bq-gzVZ14XiYIKBdHOZ&-;qhx6cfk!G#kcI90qtsbDVceG?MfB2 z>oFzs`(6uMbTtk+82x(TH~bO7=!Rdn8Qthd4c#gmZp5YvSZx8zf^C+)0aiIfX}3|m jodfBl_V2)r7ntQ)`NO9}JEQQI1M7Ktzx#)m`p*6b_bDZj literal 0 HcmV?d00001 diff --git a/content/example/assets/images/diagram.png b/content/example/assets/images/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..fe007000bc4c031d358182c3dea82726d7b8d230 GIT binary patch literal 3899 zcmb_fT}%{L6uz?MZwmp+wp|Sg)TXfFL)j1-L5kGCR@RCR0fImXofo1HB@swLk&3mr zOEyjWfNd-bnk{ux+$sS>Qn6w?^udtbl+XuAs+JfAkv7C_NYM&C=iZr}nMLF$KApLD z?mg!_-?{gkbM1!;-;dUB(-T6X3-;v|5u!Uo$d+#-LSSY(vAK?rn2>_J_lg@Q|C;Rc zd{!2f&pp0SeS72{2OLHIb{qbxsH%c%OuN)i4fjE2q@dEL=d=t6Y}X5C0U%tP)WqPP8l0`gCu|fe%#I}LQ*CP^+v&@-bnWs!fw!{2pee1 zLPS&~0jyaxO9l8SxZ}Zks4!!Sn|>1)h496W_JE|g&8g^&jYElhN8AiLN;LYai-Bh{ zCtSM%L26eJjR`Q>l5_tnSVQ5cWL5lz;S41s6wpsuU@{l{VFWNqz>g71fg}aD$|wa9 z;oreXQm+h#2PaHx3hC3D+LO4Z?~GQNUbFt+#Y5Fv{9t7KAZ?pn>WQBmlQ+t_di1`~B%@50dYN^kws(j69O>xUiuc&caYaE~z~O`P!0*|}aJ z)d_=|>arf=HEVA@EQ=m(TF5>D3;V1oFxYB@InP+Cv!tEVfx=#ctJGeSWji0_mpJ8*0Aa96W|BxR;$Bht(m^AnuCt=w@|mSA*>CQ_6}HUz|G;# z8ee}3^&JO6uB)+1@KE2)RIMATU+HPSF4Qjb1&C&MmobC^B04FRYlB6?biaT>MiEfi zFHXc$UcupjI#{OS1xZ?k7s|N`Eb^iTs|45SpM&UMvtAyvLo~ytC;XR8a&)C|1bzV^ zjG7v3orc)woGEp5gU{5e;a$HQct%?Wt>V<-vx8$zJ5eL1E`B@{&SjxvEIFk4rJ)XQ z1s?iVW4_~f5(|xun=j3(?SZ2b#v9DDL-e4)|I@OTSeK0xJ$UE@6K_zfz-<|6DV8|b zJx@J7QmAsQ~-d)=utZ-m>PGYU04k+V17ZSw_9#iu)DW{Q0mR9v&=`4vCNKktV^)~?y}?) z6oh9^sw0DWFA9j&x`Rh!tI@^@Zgfm0lqplq4*c9NR%SnxNo@m~fF4|C=X_P)+_WU# zV(BxGYCdUa*nM5}Qo-E{{0hoKo4hP56R>289TsiE!;Hdr1Sbk_(*kBwnj~ogUffL+ zvXW?(Ur-SSSQ!XZ3%pY6$xn*96?vP{udO2+b_44Gs(@-1l+ha?kEt^{RG%xqUAh|N z$K8ukX<}7jQ}Mu<1{cJDBTA`TQJa8vZMsKA&nU2>)5Utz6 zbDwkKR8tF<`F_Ztzn_#+D7I#p2c)*{$DdwQ0~Pl|8mMlaw#DKN!7bK`Zf;NFqy4H5 zR&F7$L}Jssp?w&3oLQGBNzJyEst;GEpb zvyT41X6?HHM>mpb56e1!SVlY8)t(BC2QY%lD<$}`L7w+YftrfDTOHjoP_p4gAU`|k z0}qA)3GrnQHh{L-hZiV&oIr?;BSe4~;6^33+XOMiy2zSxKF8w32W;n)CBaQU_FsQ_ YsQJm{{Zjou@F*q)`Gt8u?5#fiKjz!dzyJUM literal 0 HcmV?d00001 diff --git a/content/example/assets/images/flow.puml b/content/example/assets/images/flow.puml new file mode 100644 index 0000000..e5f2c5a --- /dev/null +++ b/content/example/assets/images/flow.puml @@ -0,0 +1,18 @@ +@startuml +skinparam backgroundColor #FFFFFF +skinparam defaultFontName "Times New Roman" +skinparam shadowing false + +title Пример схемы PlantUML + +start +:Исходный Markdown; +:Разбор директив; +if (Есть схема .puml?) then (да) + :Рендеринг через plantuml.jar; +else (нет) + :Вставка готового PNG; +endif +:Сборка документа; +stop +@enduml diff --git a/content/example/assets/images/scheme.png b/content/example/assets/images/scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..ab6a3a770d9a10c9ecb3bcfbfe932cf357d7f7bb GIT binary patch literal 3900 zcmb_feMnnZ6u)Vzt)i_TDP+R%W3;*mVkW{2y4kAf%pY;DsB_A|rWCizuq=iuuC2Px zCgD*SOmM?QA(Mv1bS<`&QdwWOxNc)4AOUH|Lm>Kx zd(Q9t&b{Zu^0xkXVtiUWAtbT#t@0Cu$S)Bh`)dClSeZ`$*ht7hd1d+0>b6IJJ-Xrk zv@W57Q4KO_j{U*Gn4dd|#giQO!$k8>_b@HniZ3>M1J4e8zxjF60m!!>6C6qR<2vLHy06I`GK z@G{AP7X^LdWhwX(Wjuf2m~;of6KRs}M53jpBqjut%ZoBIv$gM$^nzal2V;&z;s*ui z_k9zW|2{jp-s2rBI7O{a>fTv#D;!>qg0nIK_+u{#JWO>M{HhzeiI!f2|0QMZt6KNC z%2s1#g7pV%H)bKTT6!8WeH$v2X%b*H#m@lV%DSW~&j-yKpG<_8{* z=+tL=>xNPtvC|0&E`_7^gI=#{%n9o7kEKSVKGW#siaYdd{ZNet*1X(xJOcalY+7GI zzF-y9nL<_r9%omP&)!tU)*r5&9X`Qo8vGJUJmP zal5&a0FXqkUs=I+-yTQ11^G$f0_GQF+MpN}-rfd6sW+Rg zKCacE34vvLwSjxl0=P?)PiABgjL%w>#sG17xzcEN@M?5*ffHyoOej?*UCk}-@Q#ff z2;C7Zr;ysH|I2f?R-2cShxzmwN;OMYXDIf?ISYMM@U}vqqO#B~AIruB95O}ejZAo$ zQ6PavC5j;AbIhigB>4nuV%U*G;ZnDuHX-ei=^iWb#sX`K zbg_>Q94&)FRS*lT!GG>LU+cn%if95A%HCEEo}N{j^6Y^JQ07ZI+H&9fO-P~8&%i^0 zKYUv^_~(mipwf@NkOr!V0KOe{a|?@^_n`fv{j;QXT>g^wzS7R`dHvi}VRBUW3vq(6pk8(i9PXIsjytrD@5r5(Mrl{YBDtvv1MIp1Y|2$75r{$`jLq}#R{ z6*?!%A%fzRvSHZRYDxj4bjtYgpVhNavc<83AMgwcQ6d?;9Js_m&ExdR2=w0sQ0`d5 zhyg<+%1`IkJM&en1_#(XH}8_Kugq5Ljam8(reacAp)bF7tg-ulhMM6q literal 0 HcmV?d00001 diff --git a/pptx/content/assets/title-bg.jpeg b/content/example/assets/title-bg.jpeg similarity index 100% rename from pptx/content/assets/title-bg.jpeg rename to content/example/assets/title-bg.jpeg diff --git a/content/example/assets/title-page.docx b/content/example/assets/title-page.docx new file mode 100644 index 0000000000000000000000000000000000000000..d37a67555968970710a336351fc8bb82c120b718 GIT binary patch literal 31256 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 Ze2;=ODA=EygZcUc{sLh?-TwUd{{U$jdG!DQ literal 0 HcmV?d00001 diff --git a/content/example/docx/01-introduction.md b/content/example/docx/01-introduction.md new file mode 100644 index 0000000..c3a2f47 --- /dev/null +++ b/content/example/docx/01-introduction.md @@ -0,0 +1,24 @@ +Настоящий документ — демонстрационный пример, который перечисляет все возможности +генератора DOCX. Исходный текст набирается в обычных Markdown-файлах, а оформление +полностью задаётся файлом `config.yaml` в соответствии с требованиями +СТО 02068410-004-2018 [@1]. + +Документ собирается из отдельных частей, перечисленных в разделе `sections`: + +- структурные разделы без номера (введение, заключение); +- нумеруемые разделы с автоматической нумерацией заголовков; +- список использованных источников; +- приложения с буквенной нумерацией объектов. + +Основные группы возможностей: + +- форматирование текста и заголовков; +- списки, в том числе многоуровневые; +- таблицы — обычные и с подписью; +- рисунки — готовые изображения и схемы PlantUML; +- формулы с пояснениями; +- примечания, определения и перекрёстные ссылки. + +Подробное описание каждого элемента приведено в разделе 1, примеры таблиц — в +разделе 2, сводные материалы — в приложении А. Оформление ссылок на источники +приведено в соответствии с действующими стандартами [@2], [@3]. diff --git a/content/example/docx/02-features.md b/content/example/docx/02-features.md new file mode 100644 index 0000000..0e5e013 --- /dev/null +++ b/content/example/docx/02-features.md @@ -0,0 +1,104 @@ +# ВОЗМОЖНОСТИ ГЕНЕРАТОРА + +Раздел перечисляет все поддерживаемые элементы и показывает соответствующий +синтаксис Markdown. Нумерация заголовков, рисунков, таблиц и формул выполняется +автоматически. + +## Заголовки и абзацы + +Заголовок раздела задаётся одним символом `#`, подраздел — двумя `##`, пункт — +тремя `###`. Обычные абзацы разделяются пустой строкой. + +### Третий уровень + +Полужирный и курсив в оформлении по стандарту отключены, поэтому `**жирный**` и +`*курсив*` выводятся как обычный текст. + +## Списки + +- первый элемент списка; +- второй элемент с вложенными пунктами: + 1. вложенный элемент, выводимый как «а)»; + 2. ещё один вложенный элемент. + +## Таблицы + +Обычная таблица (без подписи и номера): + +| Столбец A | Столбец B | Столбец C | +|---|---|---| +| 1 | 2 | 3 | +| 4 | 5 | 6 | + +Таблица с подписью и автоматическим номером (ссылка — @tbl:features): + +::: table "Возможности оформления" id=features note="Состав приведён условно" +| Элемент | Синтаксис | Результат | +|---|---|---| +| Таблица | `::: table` | Таблица с подписью | +| Рисунок | `::: figure` | Рисунок с подписью | +| Формула | `::: formula` | Нумерованная формула | +| Примечание | `::: note` | Примечание | +| Определения | `::: definitions` | Список терминов | +::: + +## Рисунки + +Готовое изображение вставляется директивой `figure`; файл ищется относительно +каталога `paths.assets`. Пример — рисунок @fig:diagram: + +::: figure "Готовое изображение" id=diagram file=images/diagram.png +а) функциональные блоки; +б) направления связей. +::: + +Схема PlantUML рендерится автоматически из исходного файла `.puml` — рисунок +@fig:flow: + +::: figure "Схема PlantUML" id=flow file=images/flow.puml +::: + +## Формулы + +Формула с автоматическим номером и списком пояснений: + +::: formula id=efficiency +K = (T_base - T_new)/T_base +::: + +::: where +K — коэффициент снижения затрат; +T_base — исходное значение показателя; +T_new — достигнутое значение показателя. +::: + +Ссылка на формулу: @eq:efficiency. + +## Примечания и определения + +::: note +Одиночное примечание к тексту. +::: + +::: notes +- первое примечание; +- второе примечание. +::: + +::: definitions +Термин — краткое определение термина; +Второй термин — ещё одно определение. +::: + +## Перекрёстные ссылки + +Записи @fig:diagram, @tbl:features и @eq:efficiency подставляют актуальные номера +рисунка, таблицы и формулы. Ссылки на источники оформляются как [@1] или +[@2, с. 10]. + +## Разрыв страницы + +::: pagebreak +::: + +Тематический разрыв `---` также трактуется как разрыв страницы. diff --git a/content/example/docx/03-tables.md b/content/example/docx/03-tables.md new file mode 100644 index 0000000..d6e59b4 --- /dev/null +++ b/content/example/docx/03-tables.md @@ -0,0 +1,18 @@ +# ПРИМЕРЫ ТАБЛИЦ + +Раздел показывает таблицы разной размерности. Широкая таблица @tbl:wide +заполняется данными из Markdown-строк. + +::: table "Таблица с несколькими столбцами" id=wide +| № | Наименование | Тип | Значение | Единица | +|---|---|---|---|---| +| 1 | Первый параметр | Числовой | 125 | шт. | +| 2 | Второй параметр | Строковый | 18 | — | +| 3 | Третий параметр | Логический | да | — | +| 4 | Четвёртый параметр | Числовой | 420 | руб. | +::: + +После таблицы можно продолжать обычный текст и списки: + +- перечисление подтабличных пояснений; +- ещё один элемент списка. diff --git a/content/example/docx/04-conclusion.md b/content/example/docx/04-conclusion.md new file mode 100644 index 0000000..2e7840f --- /dev/null +++ b/content/example/docx/04-conclusion.md @@ -0,0 +1,14 @@ +Демонстрационный документ перечислил все поддерживаемые генератором элементы +оформления по СТО 02068410-004-2018 [@1]. + +Основные результаты: + +- показаны заголовки, абзацы и многоуровневые списки; +- приведены обычные и подписанные таблицы; +- вставлены готовое изображение и схема PlantUML; +- продемонстрированы формулы, примечания и определения; +- проверены ссылки на источники и перекрёстные ссылки на объекты. + +Полный набор параметров оформления задаётся в файле `config.yaml`, а состав +документа — списком `sections`. Единицы измерений приведены в соответствии с +действующим стандартом [@4]. diff --git a/content/example/docx/05-bibliography.md b/content/example/docx/05-bibliography.md new file mode 100644 index 0000000..5d47c0e --- /dev/null +++ b/content/example/docx/05-bibliography.md @@ -0,0 +1,4 @@ +- ГОСТ 7.32-2017. Система стандартов по информации, библиотечному и издательскому делу. Отчёт о научно-исследовательской работе. Структура и правила оформления. — М. : Стандартинформ, 2017. — 32 с. +- ГОСТ Р 7.0.5-2008. Библиографическая ссылка. Общие требования и правила составления. — М. : Стандартинформ, 2008. — 23 с. +- Иванов, И. И. Оформление отчётных документов : учебное пособие / И. И. Иванов. — Самара : Изд-во Самарского университета, 2019. — 184 с. +- ГОСТ 8.417-2002. Государственная система обеспечения единства измерений. Единицы величин. — М. : Стандартинформ, 2002. — 32 с. diff --git a/content/example/docx/06-appendix-a.md b/content/example/docx/06-appendix-a.md new file mode 100644 index 0000000..2aecee9 --- /dev/null +++ b/content/example/docx/06-appendix-a.md @@ -0,0 +1,17 @@ +Сводные данные приведены в таблице @tbl:app-a. Номер таблицы в приложении +получает префикс буквы приложения. + +::: table "Сводная таблица" id=app-a +| Показатель | Значение | Комментарий | +|---|---|---| +| Рисунков в приложении | 1 | См. @fig:app-a | +| Таблиц в приложении | 1 | Текущая таблица | +| Формул в приложении | 0 | — | +::: + +Схема приложения приведена на рисунке @fig:app-a: + +::: figure "Схема приложения" id=app-a file=images/scheme.png +а) элементы схемы; +б) связи между элементами. +::: diff --git a/content/example/docx/config.yaml b/content/example/docx/config.yaml new file mode 100644 index 0000000..9bcee9b --- /dev/null +++ b/content/example/docx/config.yaml @@ -0,0 +1,47 @@ +# Демонстрационный проект генератора DOCX. +# Показывает все возможности оформления отчёта по СТО 02068410-004-2018. +# Все относительные пути считаются от каталога этого файла. +# Общие ресурсы проекта лежат выше, в ../assets, и используются и для docx, и для pptx. + +document: + # Имя файла = имя проекта = имя папки проекта, в папке проекта. + output: ../example.docx + # Титульный лист — общий ресурс проекта. + titlePage: ../assets/title-page.docx + features: + updateFields: true + +paths: + # Каталог рисунков; file=images/x.png ищется здесь. + assets: ../assets + +plantuml: + enabled: true + java: auto + # plantuml.jar лежит в корне репозитория. + jar: ../../../tools/plantuml.jar + format: png + charset: UTF-8 + cache: true + cacheDir: .plantuml-cache + timeoutMs: 30000 + +# Структура документа: порядок частей и их типы. +sections: + - type: toc + - file: 01-introduction.md + type: structural + title: Введение + - file: 02-features.md + type: numbered + - file: 03-tables.md + type: numbered + - file: 04-conclusion.md + type: structural + title: Заключение + - file: 05-bibliography.md + type: bibliography + - file: 06-appendix-a.md + type: appendix + letter: А + title: Демонстрационные материалы diff --git a/content/example/pptx/config.yaml b/content/example/pptx/config.yaml new file mode 100644 index 0000000..816c413 --- /dev/null +++ b/content/example/pptx/config.yaml @@ -0,0 +1,51 @@ +# Демонстрационный проект генератора PPTX. +# Показывает все типы слайдов и все доступные блоки разметки. +# Все относительные пути считаются от каталога этого файла. +# Общие ресурсы проекта лежат выше, в ../assets, и используются и для docx, и для pptx. + +presentation: + # Имя файла = имя проекта = имя папки проекта, в папке проекта. + output: ../example.pptx + author: "Автор примера" + track: "Название трека" + +theme: + width: 13.333 + height: 7.5 + font: "Segoe UI" + backgrounds: + # Задники — общие ресурсы проекта. + title: ../assets/title-bg.jpeg + content: ../assets/content-bg.jpg + final: ../assets/final-bg.jpeg + +plantuml: + enabled: true + java: auto + # plantuml.jar лежит в корне репозитория. + jar: ../../../tools/plantuml.jar + format: png + charset: UTF-8 + cache: true + cacheDir: .plantuml-cache + timeoutMs: 30000 + +# Каталог контента — папка этого config.yaml. +content: + dir: . + +# Список слайдов: тип задаёт макет, file — Markdown-файл слайда. +slides: + - { type: title, file: slides/00-title.md } + - { type: content, file: slides/01-text.md } + - { type: content, file: slides/02-lists.md } + - { type: content, file: slides/03-table.md } + - { type: content, file: slides/04-image.md } + - { type: content, file: slides/05-puml.md } + - { type: content, file: slides/06-metrics.md } + - { type: content, file: slides/07-flow.md } + - { type: content, file: slides/08-chart.md } + - { type: content, file: slides/09-columns.md } + - { type: content, file: slides/10-notes.md } + - { type: section, file: slides/11-section.md } + - { type: final, file: slides/12-final.md } diff --git a/content/example/pptx/slides/00-title.md b/content/example/pptx/slides/00-title.md new file mode 100644 index 0000000..5e9c120 --- /dev/null +++ b/content/example/pptx/slides/00-title.md @@ -0,0 +1,3 @@ +# Генератор презентаций + +## Демонстрация возможностей diff --git a/content/example/pptx/slides/01-text.md b/content/example/pptx/slides/01-text.md new file mode 100644 index 0000000..d46f3c8 --- /dev/null +++ b/content/example/pptx/slides/01-text.md @@ -0,0 +1,5 @@ +# Форматирование текста + +Абзацы и inline-разметка: **полужирный**, *курсив*, ==акцент== и `код`. + +Строки автоматически переносятся и подгоняются под ширину слайда. diff --git a/content/example/pptx/slides/02-lists.md b/content/example/pptx/slides/02-lists.md new file mode 100644 index 0000000..659123c --- /dev/null +++ b/content/example/pptx/slides/02-lists.md @@ -0,0 +1,6 @@ +# Списки + +- пункт первого уровня; +- второй пункт с вложенными элементами: + - вложенный пункт; + - ещё один вложенный пункт. diff --git a/content/example/pptx/slides/03-table.md b/content/example/pptx/slides/03-table.md new file mode 100644 index 0000000..e29d983 --- /dev/null +++ b/content/example/pptx/slides/03-table.md @@ -0,0 +1,10 @@ +# Таблицы + +::: table +| Блок | Директива | Назначение | +|---|---|---| +| Таблица | ::: table | Данные в виде таблицы | +| Метрики | ::: metrics | Карточки с числами | +| Схема | ::: flow | Цепочка блоков | +| Диаграмма | ::: chart | График или диаграмма | +::: diff --git a/content/example/pptx/slides/04-image.md b/content/example/pptx/slides/04-image.md new file mode 100644 index 0000000..d5fcace --- /dev/null +++ b/content/example/pptx/slides/04-image.md @@ -0,0 +1,5 @@ +# Изображения + +::: image ../assets/images/diagram.png height=3.6 +Подпись под рисунком выводится курсивом. +::: diff --git a/content/example/pptx/slides/05-puml.md b/content/example/pptx/slides/05-puml.md new file mode 100644 index 0000000..98cd5ae --- /dev/null +++ b/content/example/pptx/slides/05-puml.md @@ -0,0 +1,5 @@ +# PlantUML + +::: image ../assets/images/flow.puml height=4.6 +Схема собрана автоматически из исходного файла .puml. +::: diff --git a/content/example/pptx/slides/06-metrics.md b/content/example/pptx/slides/06-metrics.md new file mode 100644 index 0000000..915bb2e --- /dev/null +++ b/content/example/pptx/slides/06-metrics.md @@ -0,0 +1,8 @@ +# Метрики + +::: metrics +4 | типа слайдов +8 | типов блоков +12 | директив разметки +100% | возможностей +::: diff --git a/content/example/pptx/slides/07-flow.md b/content/example/pptx/slides/07-flow.md new file mode 100644 index 0000000..5daa179 --- /dev/null +++ b/content/example/pptx/slides/07-flow.md @@ -0,0 +1,5 @@ +# Схема-цепочка + +::: flow +Markdown -> Разбор -> Рендеринг -> PPTX +::: diff --git a/content/example/pptx/slides/08-chart.md b/content/example/pptx/slides/08-chart.md new file mode 100644 index 0000000..6f68d48 --- /dev/null +++ b/content/example/pptx/slides/08-chart.md @@ -0,0 +1,9 @@ +# Диаграммы + +::: chart bar "Пример столбчатой диаграммы" +| Категория | Значение | +|---|---| +| Блок | 8 | +| Типы слайдов | 4 | +| Директивы | 12 | +::: diff --git a/content/example/pptx/slides/09-columns.md b/content/example/pptx/slides/09-columns.md new file mode 100644 index 0000000..17f5fed --- /dev/null +++ b/content/example/pptx/slides/09-columns.md @@ -0,0 +1,12 @@ +# Две колонки + +::: image ../assets/images/scheme.png side=left height=3.6 +Рисунок в левой колонке. +::: + +::: callout "Плашка-вывод" side=right +Внутри плашки работает ==выделение== и списки: + +- первый пункт; +- второй пункт. +::: diff --git a/content/example/pptx/slides/10-notes.md b/content/example/pptx/slides/10-notes.md new file mode 100644 index 0000000..61caaea --- /dev/null +++ b/content/example/pptx/slides/10-notes.md @@ -0,0 +1,7 @@ +# Заметки докладчика + +Текст слайда набирается как обычно, а сценарий выступления — в директиве notes. + +::: notes +Эти строки видны только в режиме заметок и не попадают на слайд. +::: diff --git a/content/example/pptx/slides/11-section.md b/content/example/pptx/slides/11-section.md new file mode 100644 index 0000000..f39a697 --- /dev/null +++ b/content/example/pptx/slides/11-section.md @@ -0,0 +1,3 @@ +# Раздел + +## Разделительный слайд diff --git a/content/example/pptx/slides/12-final.md b/content/example/pptx/slides/12-final.md new file mode 100644 index 0000000..bd3c628 --- /dev/null +++ b/content/example/pptx/slides/12-final.md @@ -0,0 +1,3 @@ +# Спасибо за внимание + +Демонстрация возможностей генератора завершена. diff --git a/docx/AGENTS.md b/docx/AGENTS.md index bd6fdac..102508c 100644 --- a/docx/AGENTS.md +++ b/docx/AGENTS.md @@ -1,145 +1,123 @@ -# AGENTS.md — генератор DocxGenerator +# AGENTS.md — работа с документом DOCX -`DocxGenerator` — автономный инструмент, который собирает отчёт в формате **DOCX** из обычных -**Markdown**-файлов по фиксированному дизайну СТО 02068410-004-2018. Поведение полностью -задаётся файлом `config.yaml`. - -Документ создан и для людей, и для ИИ-агентов: он описывает CLI, формат контента, схему -конфига и порядок сборки `.exe`. - ---- +Генератор `docx/` собирает отчёт в формате **DOCX** из обычных **Markdown**-файлов +по фиксированному дизайну СТО 02068410-004-2018. Этот файл — инструкция агенту по +созданию и правке конкретного документа. Поведение полностью задаётся `config.yaml` +проекта, менять код генератора не нужно. ## 1. Требования -- Windows (собранный `.exe` под `win-x64`). -- Node.js **только для сборки** `.exe` из исходников. Конечному пользователю Node.js не нужен. -- Готовые PNG вставляются без внешних зависимостей. Для рендеринга PlantUML (`.puml`) - нужны установленная Java (JRE 11+) и файл `plantuml.jar` (см. п. 4, `plantuml`). +- Node.js 18+, зависимости ставятся командой `npm install` в папке `docx/`. +- Windows/macOS/Linux. +- Готовые PNG вставляются без внешних зависимостей. Для рендеринга PlantUML + (`.puml`) нужны Java 11+ и файл `plantuml.jar` (см. `plantuml` в конфиге). -## 2. Состав дистрибутива +## 2. Раскладка проекта + +Проект лежит в `content/<проект>/docx/` рядом с `config.yaml`: ``` -DocxGenerator.exe # исполняемый файл -config.yaml # настройки (создаётся автоматически при первом запуске) -content/ # Markdown-файлы документа и ресурсы - *.md - assets/ - images/ # PNG для рисунков (готовятся заранее) и исходники .puml - title-page.docx # титульный лист (по умолчанию content/assets/title-page.docx) -tools/ - plantuml.jar # рендерер PlantUML (для файлов .puml) -report.docx # результат сборки (путь задаётся document.output) +content/<проект>/ +├── assets/ # общие ресурсы проекта (общие с pptx) +│ ├── title-page.docx # титульный лист +│ └── images/ # PNG-рисунки и исходники .puml +└── docx/ + ├── config.yaml # настройки документа + ├── 01-introduction.md + ├── 02-*.md + └── 05-bibliography.md ``` -Все относительные пути в `config.yaml` считаются **от каталога самого `config.yaml`**. -Сам `config.yaml` и папки ищутся **рядом с `DocxGenerator.exe`**. +Все относительные пути в `config.yaml` считаются **от каталога самого +`config.yaml`**. Если ресурсы общие с презентацией, указывайте их через `../assets` +(например, `paths.assets: ../assets`, `document.titlePage: ../assets/title-page.docx`). -В монорепозитории общий `plantuml.jar` лежит в корне, в `tools/plantuml.jar`, -поэтому репозиторный `config.yaml` задаёт `plantuml.jar: ../tools/plantuml.jar`. -Для автономного дистрибутива положите `tools/plantuml.jar` рядом с `.exe` -(значение по умолчанию при `--init` — `tools/plantuml.jar`). +Отчёт собирается в папку проекта и называется по имени проекта: +`content/<проект>/<проект>.docx`. Значение ключа `document.output` при такой +раскладке — `../<проект>.docx`. + +Структуру проекта создавайте командой `--init`: она формирует `config.yaml`, +примеры `*.md` и общий каталог `content/<проект>/assets/` (титульный лист, +изображения), который используется и генератором `pptx`. + +Готовый пример со всеми возможностями — `content/example/docx/`. ## 3. Командная строка -``` -DocxGenerator [опции] +Из корня репозитория: - --config <путь> путь к config.yaml (по умолчанию рядом с exe) - --content каталог с config.yaml, content/ и assets/ (по умолчанию рядом с exe) +``` +node docx/src/cli.js [опции] + + --config <путь> путь к config.yaml (по умолчанию config.yaml в текущем каталоге) + --content каталог проекта: config.yaml, *.md и assets/ (по умолчанию текущий) --output <путь> переопределить путь выходного .docx --check только проверить конфиг и ссылки, без записи файла - --init создать шаблон config.yaml/content/assets и выйти + --init создать шаблон config.yaml/*.md/assets и выйти --verbose подробный вывод --version показать версию --help справка ``` -Поведение: - -- Если `config.yaml` не найден, инструмент **сам создаёт** `config.yaml`, примеры `content/*.md` - и `assets/images/placeholder.png`, печатает подсказку и завершается. -- `--check` не пишет DOCX, но сообщает обо всех ошибках (битые ссылки, выход `[@n]` за границы - списка источников, отсутствующие картинки и т.п.). - -Типичный цикл работы: +Типичный цикл: ```powershell -.\DocxGenerator.exe --init # первый запуск: получить шаблон -# ... правим config.yaml и content/*.md ... -.\DocxGenerator.exe --check # проверить -.\DocxGenerator.exe # собрать report.docx +node docx/src/cli.js --content content/<проект>/docx --init # создать структуру проекта +node docx/src/cli.js --content content/<проект>/docx --check # проверить +node docx/src/cli.js --content content/<проект>/docx # собрать ``` +После любого изменения исходников (`config.yaml`, `*.md`, ресурсов `assets/`) +**пересоберите документ**, чтобы результат соответствовал исходникам. + +Если `config.yaml` не найден, инструмент сам создаёт шаблон (`config.yaml`, +примеры Markdown и общий `assets/`) и завершается. + ## 4. Схема `config.yaml` -Любой ключ можно опустить — берётся значение по умолчанию (см. `src/config/defaults.js`). +Любой ключ можно опустить — берётся значение по умолчанию (см. +`docx/src/config/defaults.js`). ### document | Ключ | Тип | Смысл | |------|-----|-------| -| `output` | string | путь выходного `.docx` | -| `titlePage` | string/null | путь к готовому `title-page.docx` (по умолчанию `content/assets/title-page.docx`); `null` — без титульника | +| `output` | string | путь выходного `.docx` (относительно `config.yaml`) | +| `titlePage` | string/null | путь к готовому `title-page.docx`; `null` — без титульника | | `features.updateFields` | bool | обновлять поля (в т.ч. оглавление) при открытии в Word | -**Титульный лист.** Берётся готовый DOCX по пути `document.titlePage` и склеивается перед -документом; между титульником и основным текстом вставляется разрыв страницы. При `--init` -создаётся пример `content/assets/title-page.docx` — замените его своим. Значение `null` -отключает титульный лист. +Титульный лист склеивается перед документом, между ним и текстом вставляется +разрыв страницы. При `--init` создаётся пример `assets/title-page.docx`. ### paths | Ключ | Смысл | |------|-------| -| `assets` | корень ресурсов; `file=images/x.png` в директивах ищется здесь (по умолчанию `content/assets`) | +| `assets` | корень ресурсов; `file=images/x.png` в директивах ищется здесь | -### output -Путь и имя выходного `.docx` задаются ключом `document.output` (по умолчанию -`report.docx`). Путь считается от каталога `config.yaml` и может быть переопределён -флагом `--output`. +### Структура и оформление -### page -`width`, `height` (DXA, 1/20 pt), `margins: {left,right,top,bottom}` (twips). A4 и поля СТО -заданы по умолчанию. - -### typography -| Ключ | Смысл | -|------|-------| -| `font` | гарнитура (по умолчанию Times New Roman) | -| `sizeBody` / `sizeTable` / `sizeSmall` | размеры в half-points (28 = 14 pt) | -| `lineSpacing` | множитель межстрочного интервала (1.5 = полуторный) | -| `color` | цвет текста (hex, без `#`) | -| `useBold` | разрешить полужирный (СТО: `false`) | -| `allowEmphasis` | разрешить курсив (СТО: `false`) | - -### headings -Интервалы/выравнивание для `struct`, `section`, `subsection`, `point` (twips). - -### captions -`figure`, `table`, `tableContinue` — префиксы и тире подписей (`Рисунок`, `Таблица`, `—`). - -### lists -`bulletChar`, `letterSuffix`, `numberSuffix`, `nestedLevelStep`, `forbiddenLetters`. - -### numbering -`figures`, `tables`, `formulas`: `global` (сквозная по документу) или `section` (в пределах -раздела, вид `1.1`). Приложения всегда имеют префикс буквы (`А.1`). - -### formula -`spacingBeforeAfter`, `whereTabPosition`. - -### table -`font`, `size`, `borderColor`, `borderSize`, `cellMargins: {top,bottom,left,right}`, -`headerFill`, `cellFill`. - -### figure -`maxWidth` (px; `null` — по ширине полосы), `maxHeight` (px). +| Раздел | Назначение | +|--------|-----------| +| `page` | `width`, `height` (DXA), `margins` (twips) | +| `typography` | `font`, `sizeBody`/`sizeTable`/`sizeSmall`, `lineSpacing`, `color`, `useBold`, `allowEmphasis`, `language` | +| `headings` | интервалы/выравнивание `struct`, `section`, `subsection`, `point` | +| `captions` | префиксы и тире подписей `figure`, `table`, `tableContinue` | +| `lists` | `bulletChar`, `letterSuffix`, `numberSuffix`, `nestedLevelStep`, `forbiddenLetters` | +| `numbering` | `figures`, `tables`, `formulas`: `global` или `section` | +| `formula` | `spacingBeforeAfter`, `whereTabPosition` | +| `table` | `font`, `size`, `borderColor`, `borderSize`, `cellMargins`, `headerFill`, `cellFill` | +| `figure` | `maxWidth` (px, `null` — по ширине), `maxHeight` (px) | +| `pageNumber` | `align`, `format`, `startFrom` | +| `toc` | `enabled`, `title`, `depth` (1..3) | +| `bibliography` | `title` | +| `citation` | `bracketOpen`, `bracketClose`, `pagePrefix` | +| `appendix` | `labelPrefix`, `forbiddenLetters` | ### plantuml -Генерация рисунков из исходников PlantUML (см. п. 5, «Рисунки»). | Ключ | Тип | Смысл | |------|-----|-------| -| `enabled` | bool | включить рендеринг `.puml`; `false` — считать ошибкой при наличии `.puml` | -| `java` | string | исполняемый файл Java; `auto` — `%JAVA_HOME%\bin\java`, иначе `java` из PATH | +| `enabled` | bool | включить рендеринг `.puml`; `false` — считать ошибкой | +| `java` | string | `auto` — `%JAVA_HOME%\bin\java`, иначе `java` из PATH | | `jar` | string | путь к `plantuml.jar` (относительно `config.yaml`) | | `format` | string | только `png` | | `charset` | string | кодировка исходника (по умолчанию `UTF-8`) | @@ -147,43 +125,31 @@ DocxGenerator [опции] | `cacheDir` | string | каталог кэша PNG (относительно `config.yaml`) | | `timeoutMs` | int | таймаут рендера одной диаграммы, мс | -Ошибки рендера (нет `jar`, нет Java, синтаксическая ошибка) — **фатальные**: сборка -прекращается с кодом выхода `1`. Требуется установленная Java (JRE 11+) и файл -`plantuml.jar`; для части типов диаграмм нужен Graphviz либо встроенный Smlayout. - -### pageNumber -`align`, `format`, `startFrom`. - -### toc -`enabled` (bool), `title`, `depth` (1..3). Оглавление вставляется записью -`sections: [{ type: toc }]`. - -### bibliography / citation / appendix -`bibliography.title`, `citation: {bracketOpen,bracketClose,pagePrefix}`, -`appendix: {labelPrefix, forbiddenLetters}`. +Общий `plantuml.jar` репозитория лежит в `tools/plantuml.jar`; из проекта путь +вида `../../../tools/plantuml.jar`. Ошибки рендера (нет `jar`, нет Java, +синтаксическая ошибка) — фатальные: сборка останавливается с кодом `1`. ### sections — структура документа + Упорядоченный список частей: ```yaml sections: - - { type: toc } # поле оглавления - - { file: content/01-introduction.md, type: structural, title: Введение } - - { file: content/02-main.md, type: numbered } # # = 1, ## = 1.1, ### = 1.1.1 - - { file: content/03-conclusion.md, type: structural, title: Заключение } - - { file: content/04-bibliography.md, type: bibliography } - - { file: content/05-appendix-a.md, type: appendix, letter: А, title: Приложение } + - { type: toc } # поле оглавления + - { file: 01-introduction.md, type: structural, title: Введение } + - { file: 02-main.md, type: numbered } # # = 1, ## = 1.1, ### = 1.1.1 + - { file: 04-conclusion.md, type: structural, title: Заключение } + - { file: 05-bibliography.md, type: bibliography } + - { file: 06-appendix-a.md, type: appendix, letter: А, title: Приложение } ``` -Типы частей: - | type | Поведение | |------|-----------| | `toc` | вставляет оглавление (не требует `file`) | | `structural` | ненумерованный раздел (Введение/Заключение): заголовок = `title`, ЗАГЛАВНЫМИ, по центру, с новой страницы | | `numbered` | нумеруемый раздел; `#` = раздел, `##`/`###` = подраздел/пункт | | `bibliography` | список источников; нумеруется автоматически | -| `appendix` | приложение: заголовок «ПРИЛОЖЕНИЕ » + `title`, нумерация рисунков/таблиц с префиксом буквы | +| `appendix` | приложение: заголовок «ПРИЛОЖЕНИЕ » + `title`, буквенный префикс у рисунков/таблиц | ## 5. Формат контента @@ -197,12 +163,12 @@ sections: ### Пункт -> 1.1.1 Пункт ``` -Номера подставляются автоматически (Word-numbering). В `structural`/`appendix` заголовок -берётся из конфига, а заголовки внутри файла рендерятся как обычные заголовки без номера. +Номера подставляются автоматически (Word-numbering). В `structural`/`appendix` +заголовок берётся из `title`, а заголовки внутри файла рендерятся без номера. -### Абзацы, списки +### Абзацы и списки -Обычные абзацы и списки Markdown. Списки: +Обычные абзацы и списки Markdown. Пример: ```md - первый пункт; @@ -211,8 +177,8 @@ sections: 2. ещё один. ``` -Маркер вложенности выбирается автоматически: тире → `а)` → `1)`. Полужирный/курсив по -умолчанию игнорируются (СТО). +Маркер вложенности выбирается автоматически: тире → `а)` → `1)`. Полужирный и +курсив по умолчанию игнорируются (СТО). ### Таблицы @@ -237,13 +203,18 @@ sections: ::: ``` -`file` — относительно `config.paths.assets`. Если файла нет — предупреждение, подпись -всё равно выводится. +`file` — относительно `paths.assets`. Если файла нет — предупреждение, подпись +всё равно выводится. Подпись ставится под рисунком по центру: +`Рисунок N — Наименование`. Если пояснять нечего, тело директивы оставляют +пустым: -**PlantUML.** Если `file` оканчивается на `.puml` (`.plantuml`, `.pu`, `.iuml`), то файл -считается исходником PlantUML: инструмент рендерит его в PNG через локальный -`plantuml.jar` (см. `plantuml` в конфиге) и вставляет результат как обычный рисунок. -Нумерация, ссылки `@fig:id` и примечания работают так же. Пример: +```md +::: figure "Общая схема системы" id=common file=images/common.png +::: +``` + +**PlantUML.** Если `file` оканчивается на `.puml` (`.plantuml`, `.pu`, `.iuml`), +файл рендерится в PNG через `plantuml.jar` и вставляется как обычный рисунок: ```md ::: figure "Диаграмма последовательности" id=seq file=images/seq.puml @@ -252,18 +223,7 @@ sections: ::: ``` -Ошибка рендера — фатальная (код выхода `1`), `--check` тоже рендерит `.puml`. - -**Подписи по СТО.** Подпись ставится **под** рисунком по центру: `Рисунок N — Наименование` -(с прописной буквы, без точки в конце). Если на рисунке обозначены отдельные детали, -пояснительные данные размещают **над подписью** и оформляют перечислением `а)`, `б)`, `в)` — -именно так, как показано в примере выше. Если рисунок общий и пояснять нечего, указывают -только подпись `Рисунок N — Наименование`, а тело директивы оставляют пустым: - -```md -::: figure "Общая схема системы" id=common file=images/common.png -::: -``` +Ошибка рендера фатальна, `--check` тоже рендерит `.puml`. В приложениях номер рисунка получает префикс буквы: `Рисунок А.1 — Наименование`. @@ -281,8 +241,8 @@ a — коэффициент. ::: ``` -В формулах поддерживается простой синтаксис: `^` (степень), `_` (индекс), `/` (дробь). -Номер формулы ставится автоматически справа. +Поддерживается простой синтаксис: `^` (степень), `_` (индекс), `/` (дробь). Номер +формулы ставится автоматически справа. ### Примечания и термины @@ -313,56 +273,44 @@ a — коэффициент. ### Ссылки на источники -`[@1]` — ссылка на 1-й источник, `[@1, с. 96]` — с номером страницы. Список источников — -это Markdown-список в файле `type: bibliography`; порядок строк = номера источников. +`[@1]` — ссылка на 1-й источник, `[@1, с. 96]` — с номером страницы. Список +источников — Markdown-список в файле `type: bibliography`; порядок строк = номера. Ссылка вне диапазона — ошибка в `--check`. ### Перекрёстные ссылки -`@fig:id`, `@tbl:id`, `@eq:id` подставляют актуальный номер рисунка/таблицы/формулы -(например `2`, `1.1`, `А.1`). `id` задаётся в директиве. +`@fig:id`, `@tbl:id`, `@eq:id` подставляют актуальный номер рисунка/таблицы/ +формулы (например `2`, `1.1`, `А.1`). `id` задаётся в директиве. ### Блоки кода -Функция листингов удалена: fenced-блоки ``` игнорируются с предупреждением. +Fenced-блоки ``` игнорируются с предупреждением (функция листингов удалена). ## 6. Проверка и ошибки -`DocxGenerator --check` проверяет: +`--check` проверяет: -- корректность `config.yaml` (типы, существование файлов, допустимые буквы приложений); +- корректность `config.yaml` (типы, существование файлов, буквы приложений); - наличие всех `sections[].file`; - существование меток в `@fig/@tbl/@eq`; - диапазон ссылок `[@n]`; -- рендеринг всех `::: figure ... file=*.puml` (PlantUML). +- рендеринг всех `::: figure ... file=*.puml`. Ошибки печатаются списком и возвращают код выхода `1`. Предупреждения (например, отсутствующий PNG) не останавливают сборку; ошибки PlantUML — фатальные. -## 7. Сборка `.exe` из исходников +## 7. Подготовка диаграмм -```powershell -npm install -npm run build:exe # -> DocxGenerator.exe в корне (target node24-win-x64) -npm run generate # локальная сборка (node src/cli.js) -npm run check # проверка конфига и ссылок -``` - -Упаковка выполняется через `@yao-pkg/pkg`. Чтобы уменьшить размер, можно добавить -`--compress Brotli` в команду `build:exe`. - -### Подготовка диаграмм - -Готовые PNG кладутся в `content/assets/images/`. Для исходников PlantUML (`*.puml`) -инструмент рендерит PNG сам: положите исходник в `content/assets/images/`, укажите его в -`::: figure ... file=images/<имя>.puml` и поместите `plantuml.jar` в `tools/plantuml.jar` -(или задайте путь в `plantuml.jar`). Диаграммы других форматов (Mermaid, draw.io) готовятся -внешними средствами и вставляются как PNG. +Готовые PNG кладутся в общий каталог ресурсов (`content/<проект>/assets/images/`). +Исходники PlantUML (`.puml`) кладутся туда же и указываются в +`::: figure ... file=images/<имя>.puml`. Диаграммы других форматов (Mermaid, +draw.io) готовятся внешними средствами и вставляются как PNG. ## 8. Замечания по дизайну -- Дизайн фиксирован под СТО 02068410-004-2018; меняются только параметры из `config.yaml`. -- Полужирный и курсив по умолчанию отключены (`typography.useBold`, `allowEmphasis`). -- Шрифт, размеры, интервалы, отступы и подписи настраиваются в конфиге. -- Оглавление — поле Word; при открытии нажмите «Обновить поле», либо включено +- Дизайн фиксирован под СТО 02068410-004-2018; меняются только параметры из + `config.yaml`. +- Полужирный и курсив по умолчанию отключены (`typography.useBold`, + `allowEmphasis`). +- Оглавление — поле Word; при открытии нажмите «Обновить поле» либо включите `document.features.updateFields`. diff --git a/docx/README.md b/docx/README.md index a7784d8..90cd1cc 100644 --- a/docx/README.md +++ b/docx/README.md @@ -1,44 +1,29 @@ -# DocxGenerator +# SSAU Generator DOCX -Автономный генератор отчётов **DOCX** из **Markdown** по дизайну +Генератор отчётов **DOCX** из **Markdown** по дизайну [СТО 02068410-004-2018](documentation/STO_SGAU_02068410-004-2018.md). -Поведение полностью задаётся файлом `config.yaml`; путь выходного файла — ключ -`document.output`. +Содержимое задаётся Markdown-файлами и `config.yaml` проекта; путь выходного +файла — ключ `document.output`. -Полная документация: **[AGENTS.md](AGENTS.md)** — CLI, схема конфига, формат контента, -директивы и сборка `.exe`. +Полная инструкция по работе с документом: **[AGENTS.md](AGENTS.md)** — CLI, схема +конфига, формат контента, директивы и PlantUML. ## Быстрый старт ```powershell -.\DocxGenerator.exe --init # создать config.yaml, примеры content/ и content/assets/ -# ... правим config.yaml и content/*.md ... -.\DocxGenerator.exe --check # проверить ссылки и конфиг -.\DocxGenerator.exe # собрать report.docx +node docx/src/cli.js --content content/example/docx --check # проверка +node docx/src/cli.js --content content/example/docx # собрать report.docx ``` ## Разработка ```powershell npm install -npm run generate # локальная сборка report.docx -npm run check # проверка конфига и ссылок -npm run build:exe # собрать DocxGenerator.exe в корне (@yao-pkg/pkg, node24-win-x64) +npm run generate # локальная сборка (node src/cli.js) +npm run check # проверка конфига и ссылок +npm run init # создать шаблон проекта ``` -## Структура репозитория - -| Путь | Назначение | -|------|------------| -| `src/cli.js` | точка входа, разбор аргументов | -| `src/config/` | дефолты, загрузка и валидация `config.yaml`, шаблон | -| `src/markdown/` | markdown-it, директивы `:::`, инлайн-ссылки `[@n]`, `@fig/@tbl/@eq` | -| `src/render/` | сборка DOCX: стили, примитивы, нумерация, слияние титульника | -| `src/build.js` | оркестрация сборки | -| `content/` | примеры Markdown | -| `content/assets/` | PNG для рисунков, опциональный `title-page.docx` | -| `documentation/` | стандарт СТО | - -Готовые PNG кладутся в `content/assets/images/`. Исходники PlantUML (`*.puml`) можно указать -в `::: figure ... file=images/x.puml` — генератор отрендерит их в PNG через локальный -`plantuml.jar` (требуется Java 11+). +Структура кода: `src/cli.js` (точка входа), `src/config/` (дефолты, загрузка и +валидация `config.yaml`, шаблон), `src/markdown/` (markdown-it и директивы), +`src/render/` (сборка DOCX), `src/plantuml/` (рендеринг схем). diff --git a/docx/config.yaml b/docx/config.yaml deleted file mode 100644 index d36f0d2..0000000 --- a/docx/config.yaml +++ /dev/null @@ -1,145 +0,0 @@ -# Конфигурация генератора lab-gen. -# Все относительные пути считаются от каталога этого файла. -# Любой ключ можно опустить — будет использовано значение по умолчанию. - -document: - output: report.docx - titlePage: content/assets/title-page.docx - features: - updateFields: true -paths: - assets: content/assets -page: - width: 11906 - height: 16838 - margins: - left: 1701 - right: 851 - top: 1134 - bottom: 1134 -typography: - font: Times New Roman - sizeBody: 28 - sizeTable: 28 - sizeSmall: 24 - lineSpacing: 1.5 - indentFirst: 709 - color: '000000' - useBold: false - allowEmphasis: false -headings: - struct: - spacingBefore: 360 - spacingAfter: 560 - align: center - section: - spacingBefore: 920 - spacingAfter: 0 - align: left - subsection: - spacingBefore: 284 - spacingBeforeAfterSection: 240 - spacingAfter: 0 - align: left - point: - spacingBefore: 360 - spacingAfter: 0 -captions: - figure: - prefix: Рисунок - dash: — - align: center - table: - prefix: Таблица - dash: — - align: left - tableContinue: - prefix: Продолжение таблицы -lists: - bulletChar: '-' - letterSuffix: ) - numberSuffix: ) - forbiddenLetters: - - ё - - з - - й - - о - - ч - - ь - - ы - - ъ - nestedLevelStep: 360 -numbering: - figures: global - tables: global - formulas: global -formula: - spacingBeforeAfter: 360 - whereTabPosition: 720 -table: - font: Times New Roman - size: 28 - borderColor: '000000' - borderSize: 1 - cellMargins: - top: 57 - bottom: 57 - left: 113 - right: 113 - headerFill: FFFFFF - cellFill: FFFFFF -figure: - maxWidth: null - maxHeight: 620 -plantuml: - enabled: true - java: auto - jar: ../tools/plantuml.jar - format: png - charset: UTF-8 - cache: true - cacheDir: .plantuml-cache - timeoutMs: 30000 -pageNumber: - align: center - format: decimal - startFrom: 1 -toc: - enabled: true - title: Содержание - depth: 3 -bibliography: - title: Список использованных источников -citation: - bracketOpen: '[' - bracketClose: ']' - pagePrefix: с. -appendix: - labelPrefix: ПРИЛОЖЕНИЕ - forbiddenLetters: - - Ё - - З - - Й - - О - - Ч - - Ъ - - Ы - - Ь -sections: - - type: toc - - file: content/01-introduction.md - type: structural - title: Введение - - file: content/02-method.md - type: numbered - - file: content/03-spheres.md - type: numbered - - file: content/04-conclusion.md - type: structural - title: Заключение - - file: content/05-bibliography.md - type: bibliography - - file: content/06-appendix-a.md - type: appendix - letter: А - title: Сводная таблица применения метода diff --git a/docx/content/01-introduction.md b/docx/content/01-introduction.md deleted file mode 100644 index 9737791..0000000 --- a/docx/content/01-introduction.md +++ /dev/null @@ -1,41 +0,0 @@ -Объектом исследования выступает процесс выведения нового товара на рынок, -предметом — выбор метода реализации проекта по выводу новинки и его обоснование -в различных сферах деятельности. - -Актуальность работы обусловлена тем, что запуск нового товара сопровождается -высоким риском: значительная доля новинок не достигает устойчивых продаж, а -неудачный запуск приводит к прямым убыткам, потерям доли рынка и подрыву доверия -к бренду. По разным оценкам, до семи из десяти новых товаров уходят с рынка в -первые годы после появления, поэтому цена ошибки при выводе новинки особенно -велика [@1], [@2]. В этих условиях выбор управляемого и повторяемого метода -вывода товара на рынок становится практически значимой задачей: он позволяет -снизить неопределённость, распределить ресурсы проекта и своевременно отказаться -от бесперспективного направления [@7]. - -Под новым товаром в работе понимается продукт, услуга или их значимая -модификация, ранее не предлагавшиеся компанией целевой аудитории. Выведение -такого товара на рынок охватывает исследование спроса, разработку предложения, -его продвижение и получение обратной связи от клиентов. Именно комплексность -этих этапов и их взаимное влияние порождают основные риски: чем позже компания -узнаёт реакцию рынка, тем дороже исправлять допущенные ошибки [@5], [@7]. - -Целью работы является выбор метода реализации проекта по выведению нового товара -на рынок и обоснование его применимости в десяти сферах деятельности. Для -достижения цели необходимо решить следующие задачи: - -- изучить классические и гибкие методы выведения товара на рынок и их основные - ограничения; -- обосновать выбор метода Agile/Scrum применительно к запуску новинки; -- описать роли, артефакты и события выбранной методологии; -- раскрыть механизм проверки спроса через спринты и инкременты; -- обосновать применимость метода в производстве, связи, на транспорте, в - строительстве, коммерческой деятельности, юридических услугах, организации - праздников, бытовых услугах, IT-услугах и банковской сфере; -- сформулировать выводы об универсальности выбранного метода и условиях его - эффективного применения. - -При выполнении работы использованы методы системного анализа, сравнительного -анализа методов управления проектами, проектного моделирования и обобщения -практики [@3], [@4]. Структура работы соответствует поставленным задачам: первый -раздел посвящён обоснованию выбора метода, второй — его проверке в десяти сферах -деятельности, заключение содержит основные результаты и выводы. diff --git a/docx/content/02-method.md b/docx/content/02-method.md deleted file mode 100644 index 93622ab..0000000 --- a/docx/content/02-method.md +++ /dev/null @@ -1,154 +0,0 @@ -# ВЫБОР МЕТОДА ВЫВЕДЕНИЯ НОВОГО ТОВАРА НА РЫНОК - -В разделе рассматриваются основные методы реализации проекта по выведению нового -товара на рынок, формулируются критерии их сравнения и обосновывается выбор -методологии Agile/Scrum [@1], [@5]. - -## Обзор методов выведения товара на рынок - -В практике управления проектами сложились как классические, так и гибкие методы -вывода новинки на рынок. Классические подходы (Waterfall, Stage-Gate) строятся на -последовательном прохождении этапов и предполагают, что требования известны -заранее, а результат оценивается на завершающей стадии. Гибкие подходы -(Design Thinking, Lean Startup, Agile/Scrum) переносят проверку спроса внутрь -процесса и позволяют уточнять требования по мере получения отклика рынка. Краткая -характеристика методов приведена в таблице @tbl:methods. - -::: table "Сравнение методов выведения товара на рынок" id=methods -| Метод | Сущность | Основное ограничение | -|---|---|---| -| Waterfall (водопад) | последовательные этапы от идеи до запуска | поздняя обратная связь рынка | -| Stage-Gate | этапы с контрольными «воротами» go/kill | высокая стоимость стадии | -| Design Thinking | старт от потребности клиента, прототип и тест | не задаёт процесс управления | -| Lean Startup | минимальный продукт (MVP) и цикл «создать — измерить — научиться» | требует зрелой аналитики | -| Agile/Scrum | короткие итерации — спринты, готовый инкремент | нужна дисциплина команды | -| 4P (маркетинг-микс) | проработка товара, цены, каналов, продвижения | не покрывает разработку | -::: - -Сравнение методов проводится по четырём критериям: скорость получения обратной -связи, способность реагировать на изменения, стоимость проверки спроса и -прозрачность управления. Как видно из таблицы @tbl:methods, классические методы -предполагают длительный цикл и получают обратную связь рынка лишь на финальной -стадии. Для запуска нового товара, спрос на который ещё не подтверждён, это -создаёт повышенный риск: к моменту первых продаж значительная часть ресурсов уже -израсходована, а изменение требований требует дорогостоящей переработки. -Наиболее подходящим признан гибкий подход Agile и его методология Scrum [@2], -[@6]. Ключевые различия классического и гибкого подходов сведены в таблице -@tbl:compare. - -::: table "Сравнение классического и гибкого подходов" id=compare -| Критерий | Waterfall | Agile/Scrum | -|---|---|---| -| Обратная связь рынка | в конце проекта | в каждом спринте | -| Реакция на изменения | низкая | высокая | -| Готовый продукт | к концу проекта | в конце каждого спринта | -| Стоимость проверки спроса | высокая | низкая (пилотный инкремент) | -| Требования | фиксируются заранее | уточняются итеративно | -| Риск неудачного запуска | высокий | снижается поэтапно | -::: - -## Сущность методологии Agile/Scrum - -Agile — это гибкий подход к управлению проектами, закреплённый в «Манифесте -гибкой разработки» 2001 года. Манифест ставит в приоритет людей и взаимодействие -над процессами и инструментами, работающий продукт над исчерпывающей -документацией, сотрудничество с заказчиком над согласованием условий и готовность -к изменениям над следованиям первоначальному плану [@1]. На этих ценностях -строятся двенадцать принципов, важнейшими из которых для вывода нового товара -являются ранняя и частая поставка ценности, неразрывная работа бизнеса и -исполнителей и постоянная адаптация к меняющимся условиям рынка. - -Scrum — наиболее распространённая методология Agile: работа разбивается на -короткие итерации — спринты длительностью от одной до четырёх недель, каждая из -которых завершается готовым приростом продукта (инкрементом) [@2], [@3]. В основе -Scrum лежат три идеи: прозрачность (все участники видят состояние работы), -инспекция (результат регулярно проверяется) и адаптация (процесс меняется по -результатам проверки). Такой цикл «планирование — работа — проверка — улучшение» -позволяет проверять спрос небольшими порциями и снижать стоимость ошибки, что -особенно важно при запуске товара на непроверенном рынке [@3], [@4]. - -## Роли, артефакты и события Scrum - -Методология Scrum опирается на три роли, три артефакта и четыре события. Роли -отвечают за постановку целей и организацию работы, артефакты фиксируют требования -и прогресс, а события задают ритм и обеспечивают регулярную обратную связь. Роли -и артефакты приведены в таблице @tbl:scrum. - -::: table "Роли и артефакты методологии Scrum" id=scrum -| Элемент | Назначение | -|---|---| -| Product Owner | отвечает за ценность товара и ведёт Product Backlog | -| Scrum Master | убирает препятствия, следит за процессом | -| Команда разработки | 5–9 специалистов, создающих продукт | -| Product Backlog | перечень всех требований к новому товару | -| Sprint Backlog | план работ текущего спринта | -| Increment | готовый к показу прирост продукта | -::: - -Product Owner формирует и упорядочивает Product Backlog по ценности, принимает -результат спринта и представляет интересы заказчика. Scrum Master отвечает за -соблюдение правил методологии, помогает команде убирать препятствия и защищает -спринт от незапланированных работ. Команда разработки — самоорганизующаяся -группа из пяти–девяти специалистов, которая самостоятельно определяет, сколько -задач войдёт в спринт, и отвечает за качество инкремента. Каждый артефакт имеет -своё назначение: Product Backlog хранит все требования к товару, Sprint Backlog — -план текущей итерации, а Increment — готовую к показу часть продукта. Единое -понимание готовности фиксируется в критериях Definition of Done, что делает -результат спринта проверяемым. - -Цикл работы методологии при выводе товара на рынок приведён на рисунке -@fig:scrum-cycle. - -::: figure "Цикл Scrum при выводе нового товара на рынок" id=scrum-cycle file=images/scrum-cycle.puml -а) Product Backlog фиксирует требования к товару; -б) спринт завершается инкрементом; -в) Sprint Review даёт обратную связь рынка; -г) по результатам Review выполняется следующий спринт или масштабирование. -::: - -События Scrum задают ритм работы и обеспечивают инспекцию результата. Sprint -Planning открывает спринт и определяет его цель и состав работ. Daily Scrum — -короткая ежедневная встреча для синхронизации команды и выявления препятствий. -Sprint Review завершает спринт демонстрацией инкремента заказчику и рынку, а -Sprint Retrospective позволяет команде улучшить собственный процесс. Поскольку -каждый спринт заканчивается инкрементом, рынок получает способ проверить товар -до полного запуска производства и масштабных вложений. - -Результативность спринта оценивается по величине созданного инкремента и -получаемому эффекту. Скорость команды — суммарный объём задач, выполненных за -итерацию, — позволяет прогнозировать сроки вывода товара, а ожидаемый эффект -инкремента помогает сравнивать ценность планируемых улучшений с затратами на -спринт. Ожидаемый эффект рассчитывается по формуле @eq:effect. - -::: formula id=effect -E = C * V - Z -::: - -::: where -E — ожидаемый эффект спринта; -C — ценность инкремента для клиента; -V — вероятность подтверждения спроса; -Z — затраты на проведение спринта. -::: - -Положительный ожидаемый эффект служит основанием для развития товара, а -отрицательный — для корректировки состава требований. Такой расчёт делает -решение о продолжении или изменении проекта более обоснованным [@5]. - -## Обоснование выбора Scrum - -Выбор Scrum определяется рядом преимуществ применительно к выводу нового товара на -рынок [@3], [@4]: - -- рынок проверяется дешёвым инкрементом, а не дорогим запуском «с нуля»; -- обратная связь собирается в каждом спринте, что снижает риск ошибки; -- требования уточняются итеративно, поэтому изменения не приводят к переработке - всего проекта; -- прозрачность процесса обеспечивается ролями, артефактами и событиями; -- ранние пилотные продажи формируют выручку ещё до полного запуска; -- метод не зависит от отрасли и применим там, где есть клиент и обратная связь; -- скорость команды и результаты спринтов делают план развития измеримым. - -Таким образом, Agile/Scrum выбран в качестве метода реализации проекта по -выведению нового товара на рынок. Его применимость в десяти сферах деятельности -обоснована в следующем разделе. diff --git a/docx/content/03-spheres.md b/docx/content/03-spheres.md deleted file mode 100644 index 3005438..0000000 --- a/docx/content/03-spheres.md +++ /dev/null @@ -1,105 +0,0 @@ -# ОБОСНОВАНИЕ МЕТОДА AGILE/SCRUM В СФЕРАХ ДЕЯТЕЛЬНОСТИ - -В разделе обосновывается применимость метода Agile/Scrum в десяти сферах -деятельности. В каждой сфере рассматривается пример нового товара и показывается, -как его вывод на рынок организуется через спринты, пилотный инкремент и обратную -связь [@3], [@6]. Общая логика одинакова для всех сфер: сначала создаётся -ограниченный пробный продукт, затем замеряется результат, и только после этого -принимается решение о масштабировании (рисунок @fig:funnel). - -::: figure "Воронка вывода нового товара на рынок" id=funnel file=images/product-funnel.puml -а) спринт 0 уточняет требования и сегмент рынка; -б) спринты 1–2 создают минимальную версию товара; -в) спринты 3–4 проверяют спрос на ограниченной аудитории; -г) начиная со спринта 5 товар масштабируется по подтверждённым метрикам. -::: - -## Производство - -Новым товаром выступает линейка упаковки. Вместо единовременного перезапуска всех -линий выпускается пробная партия на одной линии, которая играет роль инкремента. -В ходе спринта замеряются себестоимость партии, доля брака и скорость переналадки -оборудования. Sprint Review с оптовыми покупателями показывает востребованность -новой упаковки, после чего производство масштабируется на остальные линии, а -замечания клиентов становятся задачами следующего спринта. - -## Связь - -Новый товар — тариф «Умный дом». Пилотный спринт запускает тариф для ста -абонентов, в ходе Sprint Review анализируются подключения, средний чек и отток. -Обратная связь абонентов позволяет скорректировать состав услуг и условия -подключения. По результатам обратной связи тариф дорабатывается и выводится на -массовый рынок без риска массового оттока при неудачной конфигурации. - -## Транспорт - -Новым товаром является сервис каршеринга мини-фургонов. Пилот реализуется пятью -машинами в одном районе; метрики загрузки, среднего времени аренды и спроса -оцениваются в конце спринта. Если загрузка подтверждает спрос, инкремент -признаётся успешным, и автопарк расширяется за счёт новых районов. Такой подход -позволяет проверить экономику сервиса до крупных капитальных вложений в технику. - -## Строительство - -Новый товар — модульные дома. Первый спринт предполагает возведение одного -пилотного модуля и его показ заказчикам. На Sprint Review фиксируются затраты на -монтаж, сроки и замечания по проекту, после чего они учитываются в следующем -инкременте — серийном модуле. Итеративная проверка снижает риск ошибок в типовом -проекте, который затем тиражируется на серию. - -## Коммерческая деятельность - -Новым товаром выступает подписка на наборы продуктов. Бокс-пилот на пятидесяти -клиентах позволяет измерить конверсию, средний чек и удержание. Обратная связь -покупателей формирует Sprint Backlog для доработки ассортимента и условий -подписки. Если удержание растёт, объём подписки увеличивается, а состав наборов -уточняется по отклику клиентов. - -## Предоставление юридических услуг - -Новый товар — пакет «юрфирма на аутсорсе». Пробный месяц для пяти клиентов даёт -инкремент услуги; на Sprint Review оцениваются востребованность, трудозатраты и -повторные обращения. На основе отзывов формируются тарифы и состав пакета. -Поэтапная проверка позволяет выстроить услугу под реальные ожидания клиентов, не -вкладываясь сразу в расширение штата юристов. - -## Организация праздников - -Новым товаром является онлайн-конструктор мероприятий. Один сценарий тестируется -на пробной группе клиентов; метрики вовлечённости, повторных заказов и средней -стоимости мероприятия анализируются в конце спринта. Успешный сценарий -становится основой каталога и автоматизации заказов, а непопулярные сценарии -исключаются без затрат на массовое продвижение. - -## Предоставление бытовых услуг - -Новый товар — подписка на уборку. Пилот с двадцатью подписчиками в одном районе -позволяет измерить удержание, среднее число заказов и загрузку исполнителей. По -результатам спринта сервис дорабатывается и масштабируется на другие районы. -Пилотный формат помогает наладить логистику и стандарты качества до выхода на -городской уровень. - -## IT-услуги - -Новым товаром выступает модуль SaaS-платформы. Бета-версия для десяти клиентов -является инкрементом; на Sprint Review собираются метрики использования, частоты -ошибок и NPS. Обратная связь определяет состав следующего релиза и приоритеты -доработки. Такой цикл соответствует самой природе гибкой разработки и позволяет -выпускать ценность небольшими, но регулярными порциями. - -## Банковские услуги - -Новый товар — вклад «Цель» в мобильном приложении. Тест на ограниченной группе -пользователей позволяет оценить долю открытий, средний срок и удержание. Даже в -регулируемой сфере спринты обеспечивают безопасную проверку спроса до полного -внедрения: пилот проводится в контролируемых условиях, а результат проходит -согласование с подразделениями банка. - -## Обобщение по сферам - -Рассмотренные примеры показывают, что различия между сферами касаются в первую -очередь содержания товара и применяемых метрик, тогда как структура процесса -остаётся общей. Везде выделяются заказчик, готовый участвовать в проверке -инкремента, и измеримый результат спринта, на основании которого принимается -решение о продолжении работы. Именно эта общность позволяет считать Agile/Scrum -универсальным методом выведения нового товара на рынок [@3], [@6]. diff --git a/docx/content/04-conclusion.md b/docx/content/04-conclusion.md deleted file mode 100644 index 6f6bbc1..0000000 --- a/docx/content/04-conclusion.md +++ /dev/null @@ -1,37 +0,0 @@ -В работе выбран метод реализации проекта по выведению нового товара на рынок и -обоснована его применимость в десяти сферах деятельности. - -В результате сравнительного анализа методов установлено, что классические подходы -(Waterfall, Stage-Gate) предполагают длительный цикл и позднюю обратную связь -рынка, что повышает риск запуска новинки. Сравнение по критериям скорости -обратной связи, реакции на изменения, стоимости проверки спроса и прозрачности -управления (таблица @tbl:compare) показало, что для непроверенного рынка -предпочтителен гибкий подход. В качестве метода выбран Agile/Scrum, поскольку он -проверяет спрос дешёвым инкрементом в каждом спринте и позволяет корректировать -товар по отклику рынка. - -Показано, что методология Scrum опирается на роли (Product Owner, Scrum Master, -команда разработки), артефакты (Product Backlog, Sprint Backlog, Increment) и -события (Sprint Planning, Daily Scrum, Sprint Review, Sprint Retrospective), что -делает процесс прозрачным и управляемым [@2], [@3]. В работе раскрыт механизм -оценки результативности итераций: ожидаемый эффект спринта рассчитывается по -формуле @eq:effect, а решение о развитии товара принимается по результатам Sprint -Review. Такой подход заменяет один дорогой запуск серией последовательных -проверок и снижает стоимость возможной ошибки. - -Обоснована применимость метода в производстве, связи, на транспорте, в -строительстве, коммерческой деятельности, юридических услугах, организации -праздников, бытовых услугах, IT-услугах и банковских услугах. В каждой сфере -вывод товара на рынок строится по единой логике: ограниченный пробный продукт — -замер результата — масштабирование. Различия касаются содержания товара и набора -метрик, тогда как структура процесса и роль обратной связи остаются неизменными. - -Практическая значимость работы состоит в том, что предложенный метод можно -применять как типовой алгоритм: выделить сегмент и требования, создать MVP, -провести пилот, измерить результат и принять решение о масштабировании. Это -позволяет компании управлять риском запуска новинки и обосновывать вложения -перед расширением производства или сервиса. - -Таким образом, выбранный метод Agile/Scrum является универсальным и позволяет -снизить риск и стоимость ошибки при выведении нового товара на рынок в различных -сферах деятельности. diff --git a/docx/content/05-bibliography.md b/docx/content/05-bibliography.md deleted file mode 100644 index ead8926..0000000 --- a/docx/content/05-bibliography.md +++ /dev/null @@ -1,7 +0,0 @@ -- Манифест гибкой разработки программного обеспечения. — 2001. — URL: https://agilemanifesto.org (дата обращения: 01.10.2026). -- Schwaber K., Sutherland J. The Scrum Guide: The Definitive Guide to Scrum. — 2020. — URL: https://scrumguides.org (дата обращения: 01.10.2026). -- Сазерленд Дж. Scrum. Революционный метод управления проектами. — М.: Манн, Иванов и Фербер, 2016. — 288 с. -- ГОСТ Р 54869-2011. Проектный менеджмент. Требования к управлению проектом. — М.: Стандартинформ, 2011. — 9 с. -- Cooper R. G. Perspective: The Stage-Gate Idea-to-Launch Process. — Journal of Product Innovation Management, 2008. — Vol. 25. — P. 213–232. -- Рис Э. Бизнес с нуля. Lean Startup для быстрого тестирования идей. — М.: Альпина Паблишер, 2014. — 253 с. -- Котлер Ф. Основы маркетинга. Краткий курс. — М.: Вильямс, 2019. — 496 с. diff --git a/docx/content/06-appendix-a.md b/docx/content/06-appendix-a.md deleted file mode 100644 index d118f10..0000000 --- a/docx/content/06-appendix-a.md +++ /dev/null @@ -1,17 +0,0 @@ -Сводная характеристика применения метода Agile/Scrum в десяти сферах деятельности -приведена в таблице @tbl:sphere-summary. - -::: table "Применение метода Agile/Scrum в сферах деятельности" id=sphere-summary -| № | Сфера | Новый товар | Пилотный инкремент спринта | -|---|---|---|---| -| 1 | Производство | новая линейка упаковки | пробная партия на одной линии | -| 2 | Связь | тариф «Умный дом» | пилот на 100 абонентов | -| 3 | Транспорт | каршеринг мини-фургонов | пять машин в одном районе | -| 4 | Строительство | модульные дома | один пилотный модуль | -| 5 | Коммерческая деятельность | подписка на наборы продуктов | бокс-пилот на 50 клиентов | -| 6 | Юридические услуги | пакет «юрфирма на аутсорсе» | пробный месяц для 5 клиентов | -| 7 | Организация праздников | онлайн-конструктор мероприятий | один сценарий на пробной группе | -| 8 | Бытовые услуги | подписка на уборку | 20 подписчиков в одном районе | -| 9 | IT-услуги | модуль SaaS-платформы | бета на 10 клиентов | -| 10 | Банковские услуги | вклад «Цель» в приложении | тест на группе пользователей | -::: diff --git a/docx/content/assets/images/product-funnel.puml b/docx/content/assets/images/product-funnel.puml deleted file mode 100644 index 8d70ad1..0000000 --- a/docx/content/assets/images/product-funnel.puml +++ /dev/null @@ -1,19 +0,0 @@ -@startuml -skinparam defaultFontName "Times New Roman" -skinparam defaultFontSize 13 -skinparam shadowing false -skinparam ArrowColor #1B87C9 -skinparam rectangleBorderColor #1B87C9 -skinparam rectangleBackgroundColor #EAF4FB - -title Воронка вывода нового товара на рынок - -rectangle "Идея и исследование рынка\nСпринт 0" as A -rectangle "MVP — минимальный товар\nСпринты 1–2" as B -rectangle "Пилот на ограниченной аудитории\nСпринты 3–4" as C -rectangle "Масштабирование товара\nСпринты 5 и далее" as D - -A --> B : спрос подтверждён -B --> C : инкремент принят -C --> D : метрики достигнуты -@enduml diff --git a/docx/content/assets/images/scrum-cycle.puml b/docx/content/assets/images/scrum-cycle.puml deleted file mode 100644 index 0791e3e..0000000 --- a/docx/content/assets/images/scrum-cycle.puml +++ /dev/null @@ -1,26 +0,0 @@ -@startuml -skinparam defaultFontName "Times New Roman" -skinparam defaultFontSize 13 -skinparam shadowing false -skinparam ArrowColor #1B87C9 -skinparam rectangleBorderColor #1B87C9 -skinparam rectangleBackgroundColor #EAF4FB - -title Цикл Scrum при выводе нового товара на рынок - -rectangle "Product Backlog — требования к товару" as PB -rectangle "Sprint Planning" as SP -rectangle "Спринт 1–4 недели" as S -rectangle "Increment — пробный продукт" as I -rectangle "Sprint Review — обратная связь рынка" as R -rectangle "Sprint Retrospective" as RET -rectangle "Масштабирование товара" as M - -PB --> SP -SP --> S -S --> I -I --> R -R --> RET -RET --> SP : следующий спринт -R --> M : спрос подтверждён -@enduml diff --git a/docx/content/assets/title-page.docx b/docx/content/assets/title-page.docx deleted file mode 100644 index ad44a2ca16e3005cf4c765c91058245bc9e1b32a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6436 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 diff --git a/docx/package-lock.json b/docx/package-lock.json index 2554eff..3e7b99f 100644 --- a/docx/package-lock.json +++ b/docx/package-lock.json @@ -1,11 +1,11 @@ { - "name": "docxgenerator", + "name": "ssau-generator-docx", "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "docxgenerator", + "name": "ssau-generator-docx", "version": "2.0.0", "dependencies": { "docx": "^9.5.0", @@ -15,640 +15,7 @@ "markdown-it": "^14.1.0" }, "bin": { - "docxgenerator": "src/cli.js" - }, - "devDependencies": { - "@yao-pkg/pkg": "^6.23.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", - "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.8", - "@babel/types": "^7.29.8", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", - "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.8" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", - "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.8", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.8", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.8", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@roberts_lando/vfs": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@roberts_lando/vfs/-/vfs-0.3.3.tgz", - "integrity": "sha512-YjkxVSLw5WMZQoARaryRAjcxA+GbBzWMJdwYZX5oLUt9cC/gew9as4Dn7tcLzPp7BPoR221VpTZ+78TRPawnjg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 22" + "ssau-generator-docx": "src/cli.js" } }, "node_modules/@types/node": { @@ -660,382 +27,18 @@ "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@yao-pkg/pkg": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.23.0.tgz", - "integrity": "sha512-+d8iqRcmDxPpTE5fbSmsn1rShktIKvMcQGcFhwLdH15A4g2fBcRVLXppeQmu9fbF98bhYXjCOj6UTf3odXxWiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.23.0", - "@babel/parser": "^7.23.0", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", - "@roberts_lando/vfs": "^0.3.3", - "@yao-pkg/pkg-fetch": "3.6.6", - "esbuild": "^0.28.1", - "into-stream": "^9.1.0", - "multistream": "^4.1.0", - "picocolors": "^1.1.0", - "picomatch": "^4.0.2", - "postject": "^1.0.0-alpha.6", - "prebuild-install": "^7.1.1", - "resolve": "^1.22.10", - "resolve.exports": "^2.0.3", - "stream-meter": "^1.0.4", - "tar": "^7.5.7", - "tinyglobby": "^0.2.11", - "unzipper": "^0.12.3" - }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/@yao-pkg/pkg-fetch": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.6.6.tgz", - "integrity": "sha512-Nu9ytHewcV6FuH4WvdpYZxz2XwiP2p30jlPBzbvwsS3OPYN7RRTyGrXhcmhS59O3AdXz/LW+4bozhV3alN+MEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.0", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^3.1.1", - "undici": "^7.28.0", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, - "node_modules/b4a": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz", - "integrity": "sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, - "node_modules/bare-events": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", - "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "bare-abort-controller": "*" - }, - "peerDependenciesMeta": { - "bare-abort-controller": { - "optional": true - } - } - }, - "node_modules/bare-fs": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.8.2.tgz", - "integrity": "sha512-+ZI68KHMUvosXfKbg/UOHK0tbCdRnegbvPEdEcZ3Nd6TetieQsJPRXBRXPdLyy8+3VSEbPXtsumTpEtt78xv9w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.5.4", - "bare-path": "^3.0.0", - "bare-stream": "^2.6.4", - "bare-url": "^2.2.2", - "fast-fifo": "^1.3.2" - }, - "engines": { - "bare": ">=1.28.0" - }, - "peerDependencies": { - "bare-buffer": "*" - }, - "peerDependenciesMeta": { - "bare-buffer": { - "optional": true - } - } - }, - "node_modules/bare-path": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.2.tgz", - "integrity": "sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/bare-stream": { - "version": "2.13.4", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.4.tgz", - "integrity": "sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.8.1", - "streamx": "^2.25.0", - "teex": "^1.0.1" - }, - "peerDependencies": { - "bare-abort-controller": "*", - "bare-buffer": "*", - "bare-events": "*" - }, - "peerDependenciesMeta": { - "bare-abort-controller": { - "optional": true - }, - "bare-buffer": { - "optional": true - }, - "bare-events": { - "optional": true - } - } - }, - "node_modules/bare-url": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.5.4.tgz", - "integrity": "sha512-Gxa7UVWBr0/edU1b+TJhn/AZvMQUj9OGspvYsaTYQrAbZA4BOTZGL3LiZxvD+CeMlDH4juwD84+eTAp/bLYW5g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-path": "^3.0.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, "node_modules/docx": { "version": "9.7.1", "resolved": "https://registry.npmjs.org/docx/-/docx-9.7.1.tgz", @@ -1072,33 +75,6 @@ "pako": "~1.0.2" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -1111,169 +87,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events-universal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.7.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", - "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -1284,40 +97,6 @@ "minimalistic-assert": "^1.0.1" } }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -1330,65 +109,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/into-stream": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-9.1.0.tgz", - "integrity": "sha512-DRsRnQrbzdFjaQ1oe4C6/EIUymIOEix1qROEJTF9dbMq+M4Zrm6VaLp6SD/B9IsiEjPZuBSnWWFN+udajugdWA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", - "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/js-yaml": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", @@ -1411,32 +137,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -1510,112 +210,12 @@ "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", "license": "MIT" }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC" }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/multistream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/nanoid": { "version": "5.1.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", @@ -1634,200 +234,18 @@ "node": "^18 || >=20" } }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-abi": { - "version": "3.96.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz", - "integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postject": { - "version": "1.0.0-alpha.6", - "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", - "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^9.4.0" - }, - "bin": { - "postject": "dist/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC" - }, - "node_modules/prebuild-install/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz", - "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/prebuild-install/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -1837,22 +255,6 @@ "node": ">=6" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -1868,48 +270,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -1925,94 +285,12 @@ "node": ">=11.0.0" } }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.1.4" - } - }, - "node_modules/streamx": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", - "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2022,229 +300,24 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar": { - "version": "7.5.22", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", - "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tar-fs": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.3.tgz", - "integrity": "sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" - } - }, - "node_modules/tar-stream": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.2.tgz", - "integrity": "sha512-+8NeqHRjQWH9nYlwo2gamAMImZCVzI4UoEgDpWorBt9OEfppiZn+uSkskzQKPWIZyji/C8fpWO7u69G0DX0tbg==", - "dev": true, - "license": "MIT", - "dependencies": { - "b4a": "^1.9.0", - "bare-fs": "^4.8.2", - "fast-fifo": "^1.3.2", - "streamx": "^2.28.1" - } - }, - "node_modules/teex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "streamx": "^2.12.5" - } - }, - "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, - "node_modules/undici": { - "version": "7.30.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.0.tgz", - "integrity": "sha512-dkrQXeHSaoamnItlYbmzG0wFYrM0ZwDxCIg0A7aKjTyyhh9svRzCNFEzV+Vm05/yehjCzjDZ31KXfGEjYSztDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, "node_modules/undici-types": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unzipper": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", - "integrity": "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "bluebird": "~3.7.2", - "duplexer2": "~0.1.4", - "fs-extra": "11.3.1", - "graceful-fs": "^4.2.2", - "node-int64": "^0.4.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -2272,55 +345,6 @@ "engines": { "node": ">=0.1" } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/yargs": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", - "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } } } } diff --git a/docx/package.json b/docx/package.json index 9eff14d..358b98e 100644 --- a/docx/package.json +++ b/docx/package.json @@ -1,16 +1,16 @@ { - "name": "docxgenerator", + "name": "ssau-generator-docx", "version": "2.0.0", "private": true, - "description": "DocxGenerator — автономный генератор отчётов DOCX из Markdown по СТО 02068410-004-2018", + "description": "SSAU Generator DOCX — автономный генератор отчётов DOCX из Markdown по СТО 02068410-004-2018", "bin": { - "docxgenerator": "src/cli.js" + "ssau-generator-docx": "src/cli.js" }, "main": "src/index.js", "scripts": { "generate": "node src/cli.js", "check": "node src/cli.js --check", - "build:exe": "pkg . --targets node24-win-x64 --compress Brotli --output DocxGenerator.exe" + "init": "node src/cli.js --init" }, "dependencies": { "docx": "^9.5.0", @@ -18,16 +18,5 @@ "js-yaml": "^4.1.0", "jszip": "^3.10.1", "markdown-it": "^14.1.0" - }, - "devDependencies": { - "@yao-pkg/pkg": "^6.23.0" - }, - "pkg": { - "scripts": [ - "src/**/*.js" - ], - "targets": [ - "node24-win-x64" - ] } } diff --git a/docx/src/cli.js b/docx/src/cli.js index ad3aa04..2cb1f2e 100644 --- a/docx/src/cli.js +++ b/docx/src/cli.js @@ -14,17 +14,17 @@ const { ConfigError } = require('./util/errors'); const VERSION = '2.0.0'; -const HELP = `DocxGenerator ${VERSION} — генератор DOCX из Markdown (СТО 02068410-004-2018) +const HELP = `SSAU Generator DOCX ${VERSION} — генератор DOCX из Markdown (СТО 02068410-004-2018) Использование: - DocxGenerator.exe [опции] + node docx/src/cli.js [опции] Опции: - --config <путь> Путь к config.yaml (по умолчанию рядом с exe) - --content Каталог с config.yaml, content/ и assets/ (по умолчанию рядом с exe) + --config <путь> Путь к config.yaml (по умолчанию config.yaml в текущем каталоге) + --content Каталог проекта: config.yaml, *.md и assets/ (по умолчанию текущий) --output <путь> Переопределить путь выходного .docx --check Только проверить конфиг и ссылки, без записи - --init Создать шаблон config.yaml/content/assets и выйти + --init Создать шаблон config.yaml/*.md/assets и выйти --verbose Подробный вывод --version Показать версию --help Показать эту справку @@ -70,7 +70,7 @@ function parseArgs(argv) { } function defaultBaseDir() { - return process.pkg ? path.dirname(process.execPath) : process.cwd(); + return process.cwd(); } async function main() { @@ -101,7 +101,7 @@ async function main() { logger.info('Файлы уже существуют, ничего не создано.'); } logger.info(''); - logger.info('Отредактируйте config.yaml и файлы в content/, затем запустите DocxGenerator.exe снова.'); + logger.info('Отредактируйте config.yaml и файлы *.md, затем запустите генератор снова.'); return 0; } diff --git a/docx/src/config/defaults.js b/docx/src/config/defaults.js index f4d37af..29283c3 100644 --- a/docx/src/config/defaults.js +++ b/docx/src/config/defaults.js @@ -7,12 +7,12 @@ const DEFAULT_CONFIG = { document: { output: 'report.docx', - titlePage: 'content/assets/title-page.docx', + titlePage: 'assets/title-page.docx', features: { updateFields: true }, }, paths: { - assets: 'content/assets', + assets: 'assets', }, page: { @@ -28,6 +28,7 @@ const DEFAULT_CONFIG = { sizeSmall: 24, lineSpacing: 1.5, indentFirst: 709, + language: 'ru-RU', color: '000000', useBold: false, allowEmphasis: false, @@ -111,19 +112,19 @@ const DEFAULT_CONFIG = { sections: [ { type: 'toc' }, - { file: 'content/01-introduction.md', type: 'structural', title: 'Введение' }, - { file: 'content/02-analysis.md', type: 'numbered' }, - { file: 'content/03-design.md', type: 'numbered' }, - { file: 'content/04-conclusion.md', type: 'structural', title: 'Заключение' }, - { file: 'content/05-bibliography.md', type: 'bibliography' }, + { file: '01-introduction.md', type: 'structural', title: 'Введение' }, + { file: '02-analysis.md', type: 'numbered' }, + { file: '03-design.md', type: 'numbered' }, + { file: '04-conclusion.md', type: 'structural', title: 'Заключение' }, + { file: '05-bibliography.md', type: 'bibliography' }, { - file: 'content/06-appendix-a.md', + file: '06-appendix-a.md', type: 'appendix', letter: 'А', title: 'Сводные таблицы', }, { - file: 'content/07-appendix-b.md', + file: '07-appendix-b.md', type: 'appendix', letter: 'Б', title: 'Вспомогательные материалы', diff --git a/docx/src/config/template.js b/docx/src/config/template.js index f77b280..c9e0af8 100644 --- a/docx/src/config/template.js +++ b/docx/src/config/template.js @@ -8,21 +8,53 @@ const { DEFAULT_CONFIG } = require('./defaults'); const { diagramPng, chartPng } = require('../util/png'); const { buildSampleTitlePage } = require('../render/sample-titlepage'); -const CONFIG_HEADER = `# Конфигурация генератора DocxGenerator. +const CONFIG_HEADER = `# Конфигурация генератора SSAU Generator DOCX. # Все относительные пути считаются от каталога этого файла. # Любой ключ можно опустить — будет использовано значение по умолчанию. `; -function defaultConfigYaml() { +/** Каталог генератора внутри проекта (docx/ или pptx/). */ +function isGeneratorDir(baseDir) { + const base = path.basename(baseDir).toLowerCase(); + return base === 'docx' || base === 'pptx'; +} + +/** + * Раскладка проекта: имя проекта = имя папки проекта, общие ресурсы в + * content/<проект>/assets/, результат — content/<проект>/<проект>.docx. + */ +function projectLayout(baseDir) { + const isSub = isGeneratorDir(baseDir); + const projectDir = isSub ? path.dirname(baseDir) : baseDir; + const projectName = path.basename(projectDir) || 'project'; + return { + projectDir, + projectName, + assetsRel: isSub ? '../assets' : 'assets', + assetsDir: path.join(projectDir, 'assets'), + outputRel: isSub ? `../${projectName}.docx` : `${projectName}.docx`, + }; +} + +function defaultConfigYaml(layout) { + const config = { + ...DEFAULT_CONFIG, + document: { + ...DEFAULT_CONFIG.document, + output: layout.outputRel, + titlePage: `${layout.assetsRel}/title-page.docx`, + }, + paths: { assets: layout.assetsRel }, + }; return ( CONFIG_HEADER + - yaml.dump(DEFAULT_CONFIG, { noRefs: true, lineWidth: -1, sortKeys: false }) + yaml.dump(config, { noRefs: true, lineWidth: -1, sortKeys: false }) ); } const SAMPLE = { - 'content/01-introduction.md': `Целью работы является разработка информационной системы учёта + '01-introduction.md': `Целью работы является разработка информационной системы учёта заявок для отдела технической поддержки. Актуальность темы обусловлена ростом числа обращений и необходимостью их оперативной обработки [@1]. @@ -38,7 +70,7 @@ const SAMPLE = { действующими стандартами [@3], [@4]. `, - 'content/02-analysis.md': `# АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ + '02-analysis.md': `# АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ Раздел посвящён анализу процесса обработки обращений и обоснованию требований к информационной системе. Рассматриваются участники процесса, информационные потоки и ограничения предметной @@ -147,7 +179,7 @@ T_new — среднее время обработки заявки после ::: `, - 'content/03-design.md': `# ПРОЕКТИРОВАНИЕ ИНФОРМАЦИОННОЙ СИСТЕМЫ + '03-design.md': `# ПРОЕКТИРОВАНИЕ ИНФОРМАЦИОННОЙ СИСТЕМЫ В разделе описаны архитектура, модель данных и пользовательские сценарии разрабатываемой информационной системы. @@ -275,7 +307,7 @@ N — число обращений в месяц. ::: `, - 'content/04-conclusion.md': `В ходе работы проанализирована предметная область, спроектирована архитектура информационной + '04-conclusion.md': `В ходе работы проанализирована предметная область, спроектирована архитектура информационной системы и определены показатели эффективности [@6], [@7]. Основные результаты работы: @@ -289,7 +321,7 @@ N — число обращений в месяц. соответствии с действующим стандартом [@8]. `, - 'content/05-bibliography.md': `- ГОСТ 7.32-2017. Система стандартов по информации, библиотечному и издательскому делу. Отчёт о научно-исследовательской работе. Структура и правила оформления. — М. : Стандартинформ, 2017. — 32 с. + '05-bibliography.md': `- ГОСТ 7.32-2017. Система стандартов по информации, библиотечному и издательскому делу. Отчёт о научно-исследовательской работе. Структура и правила оформления. — М. : Стандартинформ, 2017. — 32 с. - ГОСТ Р 7.0.5-2008. Библиографическая ссылка. Общие требования и правила составления. — М. : Стандартинформ, 2008. — 23 с. - Иванов, И. И. Управление ИТ-сервисами : учебное пособие / И. И. Иванов. — Самара : Изд-во Самарского университета, 2019. — 184 с. - Петров, П. П. Обзор систем Service Desk / П. П. Петров // Информационные технологии. — 2020. — № 4. — С. 25–33. @@ -299,7 +331,7 @@ N — число обращений в месяц. - ГОСТ 8.417-2002. Государственная система обеспечения единства измерений. Единицы величин. — М. : Стандартинформ, 2002. — 32 с. `, - 'content/06-appendix-a.md': `Сводные данные по обращениям за отчётный период приведены в таблице @tbl:app-a1. + '06-appendix-a.md': `Сводные данные по обращениям за отчётный период приведены в таблице @tbl:app-a1. ::: table "Сводные данные по обращениям" id=app-a1 | Номер | Дата регистрации | Категория | Приоритет | Исполнитель | Статус | Время, мин | @@ -339,7 +371,7 @@ N — число обращений в месяц. ::: `, - 'content/07-appendix-b.md': `Схема размещения компонентов системы приведена на рисунке @fig:app-b1. + '07-appendix-b.md': `Схема размещения компонентов системы приведена на рисунке @fig:app-b1. ::: figure "Схема размещения компонентов" id=app-b1 file=images/appendix-scheme.png а) узлы развёртывания; @@ -361,29 +393,22 @@ N — число обращений в месяц. }; const IMAGES = { - 'content/assets/images/architecture.png': () => diagramPng(900, 420, [46, 94, 170]), - 'content/assets/images/data-flow.png': () => diagramPng(900, 380, [28, 140, 96]), - 'content/assets/images/interface.png': () => diagramPng(820, 480, [196, 120, 32]), - 'content/assets/images/chart.png': () => chartPng(820, 420, [122, 70, 190]), - 'content/assets/images/appendix-scheme.png': () => diagramPng(900, 520, [176, 48, 64]), + 'images/architecture.png': () => diagramPng(900, 420, [46, 94, 170]), + 'images/data-flow.png': () => diagramPng(900, 380, [28, 140, 96]), + 'images/interface.png': () => diagramPng(820, 480, [196, 120, 32]), + 'images/chart.png': () => chartPng(820, 420, [122, 70, 190]), + 'images/appendix-scheme.png': () => diagramPng(900, 520, [176, 48, 64]), }; -function scaffoldFiles() { - const files = { 'config.yaml': defaultConfigYaml() }; - for (const [name, content] of Object.entries(SAMPLE)) files[name] = content; - for (const [name, make] of Object.entries(IMAGES)) { - files[name] = { binary: make() }; - } - return files; -} - -/** Создаёт config.yaml, примеры content/ и ассеты, если их ещё нет. */ +/** + * Создаёт config.yaml, примеры Markdown и общие ресурсы проекта + * (content/<проект>/assets/), если их ещё нет. + */ async function ensureScaffold(baseDir) { - const files = scaffoldFiles(); + const layout = projectLayout(baseDir); const created = []; - for (const [name, content] of Object.entries(files)) { - const target = path.join(baseDir, name); - if (fs.existsSync(target)) continue; + const write = (target, content) => { + if (fs.existsSync(target)) return; fs.mkdirSync(path.dirname(target), { recursive: true }); if (content && typeof content === 'object' && content.binary) { fs.writeFileSync(target, content.binary); @@ -391,15 +416,17 @@ async function ensureScaffold(baseDir) { fs.writeFileSync(target, content, 'utf8'); } created.push(target); - } + }; - const titlePage = path.join(baseDir, 'content', 'assets', 'title-page.docx'); - if (!fs.existsSync(titlePage)) { - fs.mkdirSync(path.dirname(titlePage), { recursive: true }); - fs.writeFileSync(titlePage, await buildSampleTitlePage()); - created.push(titlePage); + write(path.join(baseDir, 'config.yaml'), defaultConfigYaml(layout)); + for (const [name, content] of Object.entries(SAMPLE)) { + write(path.join(baseDir, name), content); } + for (const [name, make] of Object.entries(IMAGES)) { + write(path.join(layout.assetsDir, name), { binary: make() }); + } + write(path.join(layout.assetsDir, 'title-page.docx'), await buildSampleTitlePage()); return created; } -module.exports = { defaultConfigYaml, scaffoldFiles, ensureScaffold, SAMPLE }; +module.exports = { defaultConfigYaml, projectLayout, ensureScaffold, SAMPLE }; diff --git a/docx/src/config/validate.js b/docx/src/config/validate.js index 6e94084..6edc91e 100644 --- a/docx/src/config/validate.js +++ b/docx/src/config/validate.js @@ -69,6 +69,9 @@ function validateConfig(config) { if (!(typeof typography.lineSpacing === 'number' && typography.lineSpacing > 0)) { errors.push('typography.lineSpacing: ожидалось положительное число'); } + if (typography.language != null && typeof typography.language !== 'string') { + errors.push('typography.language: ожидалась строка (например, ru-RU)'); + } for (const [key, value] of Object.entries(page.margins)) { if (!Number.isInteger(value) || value < 0) { diff --git a/docx/src/render/document.js b/docx/src/render/document.js index 3e7f8c8..1ddd63d 100644 --- a/docx/src/render/document.js +++ b/docx/src/render/document.js @@ -104,7 +104,14 @@ function renderInline(ctx, inlineToken, state) { push(textRun(ctx, ' ')); break; case 'hardbreak': - push(new TextRun({ break: 1, font: ctx.typography.font, size: ctx.typography.sizeBody })); + push( + new TextRun({ + break: 1, + font: ctx.typography.font, + size: ctx.typography.sizeBody, + ...(ctx.typography.language ? { language: { value: ctx.typography.language } } : {}), + }) + ); break; case 'strong_open': flags.bold = true; diff --git a/docx/src/render/primitives.js b/docx/src/render/primitives.js index d38ed6f..14763de 100644 --- a/docx/src/render/primitives.js +++ b/docx/src/render/primitives.js @@ -46,7 +46,7 @@ function alignmentOf(name) { function textRun(ctx, text, opts = {}) { const t = ctx.typography; - return new TextRun({ + const run = { text: text == null ? '' : String(text), font: t.font, size: opts.size || t.sizeBody, @@ -54,7 +54,9 @@ function textRun(ctx, text, opts = {}) { italics: t.allowEmphasis ? Boolean(opts.italics) : false, subScript: opts.subScript || false, superScript: opts.superScript || false, - }); + }; + if (t.language) run.language = { value: t.language }; + return new TextRun(run); } function flatten(...blocks) { @@ -325,7 +327,7 @@ function tableRow(ctx, cells, isHeader = false) { children: [textRun(ctx, line, { size: t.size })], spacing: { ...ctx.typography.lineSpacingSingle, before: 0, after: 0 }, alignment: AlignmentType.LEFT, - indent: {}, + indent: { left: 0, firstLine: 0, hanging: 0 }, }) ), }) @@ -388,12 +390,22 @@ function parseSimpleFormula(text) { let last = 0; let match; while ((match = re.exec(trimmed)) !== null) { - if (match.index > last) children.push(new MathRun(trimmed.slice(last, match.index))); - const run = new MathRun(match[2]); + let prefix = trimmed.slice(last, match.index); + const token = match[2]; + // Основание — завершающий идентификатор текста перед оператором. + const tail = /^([\s\S]*?)([A-Za-zА-Яа-я0-9]+)$/.exec(prefix); + let base = ''; + if (tail) { + base = tail[2]; + prefix = tail[1]; + } + if (prefix) children.push(new MathRun(prefix)); + const baseRuns = base ? [new MathRun(base)] : []; + const scriptRun = new MathRun(token); children.push( match[1] === '_' - ? new MathSubScript({ children: [run] }) - : new MathSuperScript({ children: [run] }) + ? new MathSubScript({ children: baseRuns, subScript: [scriptRun] }) + : new MathSuperScript({ children: baseRuns, superScript: [scriptRun] }) ); last = re.lastIndex; } @@ -580,6 +592,7 @@ function pageNumberFooter(ctx) { children: [PageNumber.CURRENT], font: ctx.typography.font, size: ctx.typography.sizeBody, + ...(ctx.typography.language ? { language: { value: ctx.typography.language } } : {}), }), ], }), diff --git a/docx/src/render/styles.js b/docx/src/render/styles.js index da78114..d1a7361 100644 --- a/docx/src/render/styles.js +++ b/docx/src/render/styles.js @@ -36,6 +36,7 @@ function buildContext(config) { lineSpacing, lineSpacingSingle, indentFirst: typography.indentFirst, + language: typography.language, }, figureMaxWidthPx: figure.maxWidth != null diff --git a/pptx/AGENTS.md b/pptx/AGENTS.md index 9c97910..8d4b0f3 100644 --- a/pptx/AGENTS.md +++ b/pptx/AGENTS.md @@ -1,66 +1,94 @@ -# AGENTS.md — генератор lab-gen-pptx +# AGENTS.md — работа с презентацией PPTX -`lab-gen-pptx` собирает презентацию **PPTX** из обычных **Markdown**-файлов по -шаблону Самарского университета. Поведение задаётся файлом `config.yaml`. +Генератор `pptx/` собирает презентацию **PPTX** из обычных **Markdown**-файлов по +шаблону Самарского университета. Этот файл — инструкция агенту по созданию и +правке конкретной презентации. Поведение задаётся `config.yaml` проекта, менять код +генератора не нужно. ## 1. Требования -- Node.js 18+. +- Node.js 18+, зависимости ставятся командой `npm install` в папке `pptx/`. - Зависимости: `pptxgenjs`, `js-yaml`. -- Для директив `::: image` с файлами `.puml` — Java 11+ (берётся из - `JAVA_HOME`, иначе `java` из PATH) и файл `plantuml.jar` (см. `config.plantuml`). +- Для директив `::: image` с файлами `.puml` — Java 11+ (из `JAVA_HOME`, иначе + `java` из PATH) и файл `plantuml.jar` (см. `config.plantuml`). -## 2. Состав +## 2. Раскладка проекта + +Проект лежит в `content/<проект>/pptx/` рядом с `config.yaml`: ``` -config.yaml # настройки (тема, тексты, таблицы, список слайдов) -content/ - slides/*.md # по одному Markdown-файлу на слайд - assets/ # задники (title-bg.jpeg, content-bg.jpg, final-bg.jpeg), - # готовые PNG/JPEG и исходники PlantUML (*.puml) -presentation.pptx # результат сборки (ключ presentation.output) -.plantuml-cache/ # кэш отрендеренных PlantUML (ключ plantuml.cacheDir) -src/ # cli.js, config.js, parse.js, render.js, plantuml.js, build.js +content/<проект>/ +├── assets/ # общие ресурсы проекта (общие с docx) +│ ├── title-bg.jpeg # задники +│ ├── content-bg.jpg +│ ├── final-bg.jpeg +│ └── images/ # готовые PNG/JPEG и исходники .puml +└── pptx/ + ├── config.yaml + └── slides/ + ├── 00-title.md + └── 01-*.md ``` -Все относительные пути считаются **от каталога `config.yaml`**. +Все относительные пути считаются **от каталога `config.yaml`**. Общие с документом +ресурсы указывайте через `../assets` (например, +`backgrounds.title: ../assets/title-bg.jpeg`). Каталог контента — ключ +`content.dir` (по умолчанию `.` — папка самого `config.yaml`). -Общий `plantuml.jar` монорепозитория лежит в корне, в `tools/plantuml.jar` -(`plantuml.jar: ../tools/plantuml.jar`). Для автономного дистрибутива положите -`tools/plantuml.jar` рядом с `config.yaml` и задайте путь `tools/plantuml.jar`. +Презентация собирается в папку проекта и называется по имени проекта: +`content/<проект>/<проект>.pptx`. Значение ключа `presentation.output` при такой +раскладке — `../<проект>.pptx`. + +Структуру проекта создавайте командой `--init`: она формирует `config.yaml`, +примеры слайдов и общий каталог `content/<проект>/assets/` (задники), который +используется и генератором `docx`. + +Готовый пример со всеми возможностями — `content/example/pptx/`. ## 3. Командная строка +Из корня репозитория: + ``` -lab-gen-pptx [config.yaml] [опции] +node pptx/src/cli.js [config.yaml] [опции] -c, --config путь к config.yaml (по умолчанию config.yaml) -o, --output переопределить имя выходного файла --check только проверить конфиг и ссылки + --init создать шаблон config.yaml/slides/assets и выйти -v, --verbose подробный вывод -h, --help справка --version версия ``` +Типичный цикл: + ```powershell -npm run check -npm run generate +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --init # создать структуру проекта +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml --check # проверить +node pptx/src/cli.js -c content/<проект>/pptx/config.yaml # собрать ``` +После любого изменения исходников (`config.yaml`, слайдов, ресурсов `assets/`) +**пересоберите презентацию**, чтобы результат соответствовал исходникам. + +Если `config.yaml` не найден, инструмент сам создаёт шаблон (`config.yaml`, +примеры слайдов и общий `assets/`) и завершается. + ## 4. Схема `config.yaml` | Раздел | Назначение | |---|---| | `presentation` | `output`, `author`, `track` | | `theme` | `width`/`height` (дюймы), `font`, `colors`, `backgrounds`, `slideNumber` | -| `text` | макеты текста для типов слайдов `titleSlide`, `section`, `content`, `final` | +| `text` | макеты текста для типов `titleSlide`, `section`, `content`, `final` | | `table` | размер шрифта, цвета шапки/ячеек/границ | | `callout` | плашка-вывод: заливка, рамка, цвета и размеры шрифтов | | `metrics` | карточки-метрики: заливка, цвета, размеры значения и подписи | -| `flow` | нативная схема-цепочка: заливка, рамка, стрелки, размер | +| `flow` | схема-цепочка: заливка, рамка, стрелки, размер | | `chart` | палитра, размер шрифта, легенда, высота диаграммы | | `plantuml` | рендеринг `*.puml` (см. п. 5) | -| `content.dir` | каталог контента | +| `content.dir` | каталог контента (по умолчанию `.`) | | `slides` | список слайдов: `{ type, file }` | Типы слайдов: `title`, `section`, `content`, `final`. Каждому типу соответствует @@ -93,7 +121,7 @@ npm run generate | 1 | 2 | ::: -::: image assets/pic.png +::: image ../assets/images/pic.png подпись под рисунком ::: @@ -127,9 +155,9 @@ npm run generate ``` Параметр `side=left|right` ставит плашку в левую или правую колонку слайда. -Если у слайда есть блоки с `side`, они верстаются в две колонки (левая/правая), -а остальные блоки — как обычно. Типовое сочетание: `::: image ... side=left` -и `::: callout ... side=right`. +Если у слайда есть блоки с `side`, они верстаются в две колонки, а остальные +блоки — как обычно. Не смешивайте на одном слайде обычный текст и колонки +(`side`) — они накладываются. ### Директива `::: metrics` @@ -145,8 +173,7 @@ npm run generate ### Директива `::: flow` -Нативная схема-цепочка из скруглённых блоков со стрелками. Шаги разделяются -`->` (или `→`), можно писать по одному на строку: +Схема-цепочка из скруглённых блоков со стрелками. Шаги разделяются `->` (или `→`): ```md ::: flow @@ -154,14 +181,14 @@ Sprint Planning -> Спринт -> Sprint Review -> Ретроспектива ::: ``` -Если ширина блока становится малой, схема автоматически разворачивается +Если блоки становятся слишком узкими, схема автоматически разворачивается вертикально. ### Директива `::: chart <тип> "Заголовок"` Диаграмма на основе GFM-таблицы: первая колонка — категории, остальные — -числовые ряды (заголовки колонок = имена рядов). Поддерживаемые типы: -`bar`, `bar3d`, `line`, `pie`, `doughnut`, `area`, `radar`, `scatter`. +числовые ряды (заголовки колонок = имена рядов). Типы: `bar`, `bar3d`, `line`, +`pie`, `doughnut`, `area`, `radar`, `scatter`. ```md ::: chart doughnut "Новинки, которые не выживают" @@ -174,38 +201,38 @@ Sprint Planning -> Спринт -> Sprint Review -> Ретроспектива ### Директива `::: image` и PlantUML -`file` — относительно `content.dir` (`content/`). Если файл оканчивается на -`.puml` (`.plantuml`, `.pu`, `.iuml`), он рендерится в PNG через `plantuml.jar` -(см. `config.plantuml`) и вставляется как обычный рисунок: +`file` — относительно `content.dir`. Если файл оканчивается на `.puml` +(`.plantuml`, `.pu`, `.iuml`), он рендерится в PNG через `plantuml.jar` и +вставляется как обычный рисунок: ```md -::: image assets/scrum-cycle.puml height=3.2 +::: image ../assets/images/scrum-cycle.puml height=3.2 Цикл Scrum: от Product Backlog до масштабирования товара ::: ``` Подпись (строка под директивой) выводится под рисунком курсивом. Растровые -PNG/JPEG вставляются как есть. Необязательный параметр `height=<дюймы>` -(`h=`) ограничивает высоту рисунка, чтобы уместить под ним другие блоки; -пропорции сохраняются, рисунок центрируется. Параметр `side=left|right` -ставит рисунок в колонку (см. `::: callout`). +PNG/JPEG вставляются как есть. Параметр `height=<дюймы>` (`h=`) ограничивает +высоту рисунка (пропорции сохраняются, рисунок центрируется). `side=left|right` +ставит рисунок в колонку. ## 6. Задники -Изображения-задники извлечены из `presentation_16.pptx` в -`content/assets/` (`title-bg.jpeg`, `content-bg.jpg`, `final-bg.jpeg`). При замене -шаблона положите новые файлы и обновите пути в `theme.backgrounds`. +Задники лежат в общем каталоге ресурсов проекта +(`content/<проект>/assets/`: `title-bg.jpeg`, `content-bg.jpg`, `final-bg.jpeg`). +При замене шаблона положите новые файлы и обновите пути в `theme.backgrounds`. ## 7. Шрифт -В шаблоне используется фирменный `Elektra Text Pro`, который обычно не установлен -в системе (иначе Word подставляет случайный шрифт). Поэтому по умолчанию задан -`Segoe UI` — близкий современный sans. Альтернативы: `Calibri`, `Candara`, -`Corbel`, `Noto Sans`, `Arial`. Смените `theme.font` при необходимости. +В исходном шаблоне используется фирменный `Elektra Text Pro`, который обычно не +установлен в системе. Поэтому по умолчанию задан `Segoe UI` — близкий современный +sans. Альтернативы: `Calibri`, `Candara`, `Corbel`, `Noto Sans`, `Arial`. +Смените `theme.font` при необходимости. ## 8. Проверка результата -Презентацию можно отрендерить для визуальной проверки через LibreOffice: +`--check` проверяет конфиг и наличие слайдов/ресурсов. Презентацию можно +отрендерить для визуальной проверки через LibreOffice: ```powershell soffice --headless --convert-to pdf --outdir . presentation.pptx diff --git a/pptx/config.yaml b/pptx/config.yaml deleted file mode 100644 index 31a02df..0000000 --- a/pptx/config.yaml +++ /dev/null @@ -1,130 +0,0 @@ -# Конфигурация генератора презентаций lab-gen-pptx. -# Шаблон: Самарский университет, presentation_16.pptx. -# Все относительные пути считаются от каталога этого файла. - -presentation: - output: presentation.pptx - author: "Степанов П.А." - track: "ДОП 11" - group: "6403-020302D" - -theme: - width: 13.333 - height: 7.5 - # Шрифт презентации. Elektra Text Pro (фирменный) не установлен в системе, - # поэтому используется близкий современный sans. Замените при необходимости. - font: "Segoe UI" - colors: - white: "FFFFFF" - ink: "1F2933" - brand: "1B87C9" - muted: "6B7280" - accent: "0E6BA8" - tint: "EAF4FB" - line: "BFD3DD" - backgrounds: - title: content/assets/title-bg.jpeg - content: content/assets/content-bg.jpg - final: content/assets/final-bg.jpeg - slideNumber: - show: true - x: 12.17 - y: 6.86 - w: 0.5 - h: 0.42 - fontSize: 14 - # color — для тёмных фонов (разделитель), contentColor — для белых (контент) - color: "FFFFFF" - contentColor: "FFFFFF" - bold: true - align: "center" - -text: - titleSlide: - title: { x: 6.7, y: 1.85, w: 5.95, h: 1.9, fontSize: 28, align: center, color: white } - subtitle: { x: 6.7, y: 3.75, w: 5.95, h: 0.7, fontSize: 16, align: center, color: white } - body: { x: 6.7, y: 4.65, w: 5.95, h: 1.7, fontSize: 14, align: center, color: white } - section: - title: { x: 6.4, y: 2.55, w: 6.35, h: 2.4, fontSize: 26, bold: true, align: center, color: white } - content: - title: { x: 0.6, y: 0.20, w: 12.15, h: 0.66, fontSize: 24, align: center, color: white, valign: middle } - body: { x: 0.75, y: 0.98, w: 11.85, h: 5.7, fontSize: 18, align: left, color: ink, valign: top } - bulletSize: 18 - subBulletSize: 16 - final: - title: { x: 6.7, y: 2.85, w: 5.95, h: 1.6, fontSize: 28, bold: true, align: center, color: white } - body: { x: 6.7, y: 4.65, w: 5.95, h: 1.7, fontSize: 14, align: center, color: white } - -table: - fontSize: 14 - headerFill: "1B87C9" - headerColor: "FFFFFF" - cellColor: "1F2933" - borderColor: "BFD3DD" - -callout: - fill: "EAF4FB" - border: "1B87C9" - titleColor: "0E6BA8" - textColor: "1F2933" - titleFontSize: 18 - fontSize: 15 - lineWidth: 1.25 - -metrics: - fill: "1B87C9" - valueColor: "FFFFFF" - labelColor: "EAF4FB" - valueFontSize: 30 - labelFontSize: 13 - gap: 0.2 - height: 1.25 - -flow: - fill: "EAF4FB" - border: "1B87C9" - textColor: "1F2933" - arrowColor: "1B87C9" - fontSize: 13 - height: 1.0 - gap: 0.4 - -chart: - palette: ["1B87C9", "7FB2D9", "0E6BA8", "BFD3DD"] - fontSize: 12 - legend: true - height: 3.4 - -# Рендеринг PlantUML (::: image assets/schema.puml). -# Требуется Java 11+ (берётся из JAVA_HOME, иначе java из PATH) и plantuml.jar. -# Общий jar монорепозитория лежит в корне: tools/plantuml.jar. -plantuml: - enabled: true - java: auto - jar: ../tools/plantuml.jar - format: png - charset: UTF-8 - cache: true - cacheDir: .plantuml-cache - timeoutMs: 30000 - -content: - dir: content - -slides: - - { type: title, file: slides/00-title.md } - - { type: content, file: slides/01-agenda.md } - - { type: content, file: slides/01-task.md } - - { type: content, file: slides/02-why-scrum.md } - - { type: content, file: slides/03-roles.md } - - { type: content, file: slides/04-events.md } - - { type: content, file: slides/12-scrum-cycle.md } - - { type: content, file: slides/05-launch.md } - - { type: section, file: slides/06-spheres.md } - - { type: content, file: slides/07a-spheres-1-2.md } - - { type: content, file: slides/07b-spheres-3-4.md } - - { type: content, file: slides/07c-spheres-5-6.md } - - { type: content, file: slides/07d-spheres-7-8.md } - - { type: content, file: slides/07e-spheres-9-10.md } - - { type: content, file: slides/10-conclusion.md } - - { type: final, file: slides/11-final.md } diff --git a/pptx/content/assets/scrum-cycle.puml b/pptx/content/assets/scrum-cycle.puml deleted file mode 100644 index cd0600c..0000000 --- a/pptx/content/assets/scrum-cycle.puml +++ /dev/null @@ -1,24 +0,0 @@ -@startuml -skinparam defaultFontName "Times New Roman" -skinparam defaultFontSize 13 -skinparam shadowing false -skinparam ArrowColor #1B87C9 -skinparam rectangleBorderColor #1B87C9 -skinparam rectangleBackgroundColor #EAF4FB - -rectangle "Product Backlog — требования к товару" as PB -rectangle "Sprint Planning" as SP -rectangle "Спринт 1–4 недели" as S -rectangle "Increment — пробный продукт" as I -rectangle "Sprint Review — обратная связь рынка" as R -rectangle "Sprint Retrospective" as RET -rectangle "Масштабирование товара" as M - -PB --> SP -SP --> S -S --> I -I --> R -R --> RET -RET --> SP : следующий спринт -R --> M : спрос подтверждён -@enduml diff --git a/pptx/content/slides/00-title.md b/pptx/content/slides/00-title.md deleted file mode 100644 index f7be6c0..0000000 --- a/pptx/content/slides/00-title.md +++ /dev/null @@ -1,13 +0,0 @@ -# Современные проектные технологии - -## Метод выведения нового товара на рынок: Agile / Scrum - -Степанов П.А., группа 6403-020302D - -Слушатель программы профессиональной переподготовки «Современные проектные технологии» - -ИОТ-трек «ДОП 11» - -::: notes -Добрый день, уважаемые члены итоговой аттестационной комиссии. Меня зовут Степанов П.А., я слушатель программы профессиональной переподготовки «Современные проектные технологии», ИОТ-трек «ДОП 11», группа 6403-020302D. Разрешите представить решение итогового задания по теме «Современные проектные технологии» — метод выведения нового товара на рынок. -::: diff --git a/pptx/content/slides/01-agenda.md b/pptx/content/slides/01-agenda.md deleted file mode 100644 index a968cd7..0000000 --- a/pptx/content/slides/01-agenda.md +++ /dev/null @@ -1,12 +0,0 @@ -# План доклада - -- ==Метод== выведения нового товара: Agile / Scrum -- Почему выбран именно Scrum -- Роли, артефакты и события методологии -- Как спринты проверяют спрос на рынке -- Применение в ==десяти сферах== деятельности -- Выводы и практический результат - -::: notes -Структура доклада. Сначала я обосную выбор метода — Agile и Scrum. Затем покажу, как устроена методология: роли, артефакты и события. Отдельно объясню, как спринты позволяют проверять спрос на рынке. После этого докажу универсальность метода на десяти сферах деятельности: от производства до банковских услуг. В завершение приведу выводы и практический результат. -::: diff --git a/pptx/content/slides/01-task.md b/pptx/content/slides/01-task.md deleted file mode 100644 index f3fd8b6..0000000 --- a/pptx/content/slides/01-task.md +++ /dev/null @@ -1,19 +0,0 @@ -# Постановка задачи - -- Выбрать метод выведения нового товара на рынок -- Обосновать его применимость в ==десяти сферах== деятельности -- Показать, как метод работает в каждой сфере - -::: metrics -70% | новых товаров уходят с рынка -10 | сфер применения метода -4 | недели — максимальная длина спринта -::: - -::: callout "Проблема и решение" -Запуск новинки — это **высокий риск**. Нужен управляемый и повторяемый процесс вывода товара — таким процессом является **Agile / Scrum**. -::: - -::: notes -Задача итогового задания — выбрать метод выведения нового товара на рынок и обосновать его в десяти сферах: от производства до банковских услуг. Запуск новинки всегда сопряжён с риском: до семи из десяти новых товаров не выживают на рынке. Поэтому нужен управляемый и повторяемый процесс, и в качестве такого метода я выбрал Agile и его самую популярную методологию — Scrum. -::: diff --git a/pptx/content/slides/02-why-scrum.md b/pptx/content/slides/02-why-scrum.md deleted file mode 100644 index d68e907..0000000 --- a/pptx/content/slides/02-why-scrum.md +++ /dev/null @@ -1,18 +0,0 @@ -# Почему выбран Agile / Scrum - -- Agile — гибкий подход к управлению проектами, закреплён в ==манифесте 2001 года== -- Scrum — самая распространённая Agile-методология в мире -- Работа идёт короткими итерациями — *спринтами* от одной до четырёх недель -- Каждый спринт даёт готовый прирост продукта — ==инкремент== -- Обратная связь с рынком собирается на каждом шаге, а не в конце проекта - -::: chart doughnut "Новинки, которые не выживают на рынке" -| Итог | Доля, % | -|---|---| -| Успешные новинки | 30 | -| Уходят с рынка | 70 | -::: - -::: notes -Почему именно Agile и Scrum. Agile — это гибкий подход к управлению проектами, закреплённый в манифесте 2001 года. Scrum — самая распространённая Agile-методология. Работа разбивается на короткие спринты длиной от одной до четырёх недель. Каждый спринт завершается готовым приростом продукта. Благодаря этому обратная связь с рынком собирается постоянно, а не только в конце. Именно поэтому гибкий подход снижает риск: как показывают оценки, до семи из десяти новинок не выживают при традиционном запуске. -::: diff --git a/pptx/content/slides/03-roles.md b/pptx/content/slides/03-roles.md deleted file mode 100644 index cd9ddcc..0000000 --- a/pptx/content/slides/03-roles.md +++ /dev/null @@ -1,21 +0,0 @@ -# Scrum: роли и артефакты - -- **Product Owner** — отвечает за ценность товара и ведёт Product Backlog -- **Scrum Master** — убирает препятствия и следит за соблюдением процесса -- **Команда разработки** — от пяти до девяти специалистов, создающих продукт - -::: table -| Артефакт Scrum | Назначение | -|---|---| -| Product Backlog | все требования к новому товару | -| Sprint Backlog | план работ текущего спринта | -| Increment | готовый к показу прирост продукта | -::: - -::: callout "Прозрачность" -Все артефакты видны команде и заказчику, а критерии готовности зафиксированы в ==Definition of Done==. -::: - -::: notes -В Scrum три роли. Product Owner отвечает за ценность товара и ведёт Product Backlog — список всех требований. Scrum Master убирает препятствия и следит за соблюдением процесса. Команда разработки из пяти–девяти специалистов создаёт продукт. Три артефакта: Product Backlog со всеми требованиями, Sprint Backlog с планом текущего спринта и Increment — готовый прирост продукта. Единое понимание готовности фиксируется в критериях Definition of Done. -::: diff --git a/pptx/content/slides/04-events.md b/pptx/content/slides/04-events.md deleted file mode 100644 index 66d0ee6..0000000 --- a/pptx/content/slides/04-events.md +++ /dev/null @@ -1,18 +0,0 @@ -# Scrum: события спринта - -::: flow -Sprint Planning -> Спринт -> Sprint Review -> Ретроспектива -::: - -- **Sprint Planning** — планируем, что войдёт в спринт -- **Daily Scrum** — пятнадцать минут на синхронизацию команды -- **Sprint Review** — показываем прирост заказчику и рынку -- **Sprint Retrospective** — улучшаем процесс работы команды - -::: callout "Результат спринта" -Каждый спринт заканчивается рабочим ==инкрементом== — кандидатом на рынок. -::: - -::: notes -Спринт состоит из четырёх событий. На Sprint Planning команда решает, что войдёт в спринт. Daily Scrum — пятнадцатиминутная синхронизация каждый день. На Sprint Review прирост показывают заказчику и рынку. На Sprint Retrospective команда улучшает свой процесс. Каждый спринт заканчивается рабочим инкрементом, который можно показать рынку. Далее цикл повторяется: планирование, спринт, демонстрация, ретроспектива. -::: diff --git a/pptx/content/slides/05-launch.md b/pptx/content/slides/05-launch.md deleted file mode 100644 index 11ee86a..0000000 --- a/pptx/content/slides/05-launch.md +++ /dev/null @@ -1,18 +0,0 @@ -# Как Scrum выводит товар на рынок - -::: flow -Спринт 0: исследование -> MVP -> Пилот и метрики -> Масштабирование -::: - -- **Спринт 0** — исследование рынка, выбор сегмента, формирование Product Backlog -- **Спринты 1–2** — создание MVP: минимальной версии товара для первых клиентов -- **Спринты 3–4** — пилот на ограниченной аудитории и сбор метрик -- **Спринт 5 и далее** — доработка по обратной связи и масштабирование - -::: callout "Итог" -Рынок проверяется ==дешёвым инкрементом==, а не дорогим запуском «с нуля». -::: - -::: notes -Как Scrum выводит товар на рынок. Спринт ноль — исследование рынка и формирование списка требований. Спринты один и два — создание минимального продукта для первых клиентов. Спринты три и четыре — пилот на ограниченной аудитории и сбор метрик. Дальше — доработка по обратной связи и масштабирование. Демонстрация реальным клиентам позволяет проверить спрос до крупных вложений. Итог: рынок проверяется дешёвым инкрементом, а не дорогим запуском с нуля. -::: diff --git a/pptx/content/slides/06-spheres.md b/pptx/content/slides/06-spheres.md deleted file mode 100644 index e34fee5..0000000 --- a/pptx/content/slides/06-spheres.md +++ /dev/null @@ -1,7 +0,0 @@ -# Agile / Scrum в десяти сферах деятельности - -Обоснование универсальности выбранного метода - -::: notes -Теперь покажу, что метод Agile и Scrum применим не только в IT, но и в десяти различных сферах деятельности. -::: diff --git a/pptx/content/slides/07a-spheres-1-2.md b/pptx/content/slides/07a-spheres-1-2.md deleted file mode 100644 index 56b58d2..0000000 --- a/pptx/content/slides/07a-spheres-1-2.md +++ /dev/null @@ -1,21 +0,0 @@ -# Сферы 1–2: производство и связь - -::: callout "1. Производство — новая линейка упаковки" -- Новый товар: линейка упаковки для розницы. -- Пилотный спринт: пробная партия на ==одной линии==. -- Метрика Sprint Review: себестоимость, доля брака, скорость переналадки. -- Решение: масштабирование на остальные линии по подтверждённому спросу. -- Особенность: переналадка одной линии дешевле полного перезапуска. -::: - -::: callout "2. Связь — тариф «Умный дом»" -- Новый товар: тариф «Умный дом» для абонентов. -- Пилотный спринт: подключение ==100 абонентов==. -- Метрика Sprint Review: число подключений, средний чек, отток. -- Решение: доработка состава услуг и вывод тарифа на массовый рынок. -- Особенность: пилот ограничен абонентской базой и не грозит массовым оттоком. -::: - -::: notes -Первые две сферы. В производстве новая линейка упаковки запускается пробной партией на одной линии: замеряют себестоимость, долю брака и скорость переналадки. По результатам Sprint Review производство масштабируется на остальные линии. В связи тариф «Умный дом» тестируется на ста абонентах: анализируют подключения, средний чек и отток, после чего состав услуг уточняется и тариф выводится на массовый рынок. Общая логика: ограниченный пилот, замер метрики, затем масштабирование. -::: diff --git a/pptx/content/slides/07b-spheres-3-4.md b/pptx/content/slides/07b-spheres-3-4.md deleted file mode 100644 index 060080a..0000000 --- a/pptx/content/slides/07b-spheres-3-4.md +++ /dev/null @@ -1,21 +0,0 @@ -# Сферы 3–4: транспорт и строительство - -::: callout "3. Транспорт — каршеринг мини-фургонов" -- Новый товар: сервис каршеринга мини-фургонов. -- Пилотный спринт: ==пять машин== в одном районе. -- Метрика Sprint Review: загрузка, среднее время аренды, спрос. -- Решение: расширение автопарка и запуск в новых районах. -- Особенность: экономика сервиса проверяется до закупки техники. -::: - -::: callout "4. Строительство — модульные дома" -- Новый товар: модульные дома для застройки. -- Пилотный спринт: возведение ==одного пилотного модуля== и показ заказчикам. -- Метрика Sprint Review: затраты на монтаж, сроки, замечания. -- Решение: серийный модуль с учётом правок и тиражирование. -- Особенность: типовой проект снижает стоимость серии. -::: - -::: notes -Транспорт и строительство. В транспорте сервис каршеринга мини-фургонов стартует с пяти машин в одном районе: оценивают загрузку, среднее время аренды и спрос. Если экономика подтверждается, автопарк расширяется. В строительстве сначала возводится один пилотный модульный дом и показывается заказчикам: фиксируют затраты, сроки и замечания, после чего серийный модуль тиражируется. Итеративная проверка снижает риск ошибок в типовом проекте. -::: diff --git a/pptx/content/slides/07c-spheres-5-6.md b/pptx/content/slides/07c-spheres-5-6.md deleted file mode 100644 index d076692..0000000 --- a/pptx/content/slides/07c-spheres-5-6.md +++ /dev/null @@ -1,21 +0,0 @@ -# Сферы 5–6: коммерция и юридические услуги - -::: callout "5. Коммерция — подписка на наборы продуктов" -- Новый товар: подписка на наборы продуктов. -- Пилотный спринт: бокс-пилот на ==50 клиентах==. -- Метрика Sprint Review: конверсия, средний чек, удержание. -- Решение: доработка ассортимента и условий подписки. -- Особенность: состав набора гибко меняется по спросу. -::: - -::: callout "6. Юридические услуги — пакет «юрфирма на аутсорсе»" -- Новый товар: пакет «юрфирма на аутсорсе». -- Пилотный спринт: пробный месяц для ==5 клиентов==. -- Метрика Sprint Review: востребованность, трудозатраты, повторные обращения. -- Решение: тарифы и состав пакета формируются по отзывам. -- Особенность: расширение штата юристов только после подтверждения спроса. -::: - -::: notes -Коммерция и юридические услуги. В коммерции подписка на продуктовые наборы запускается бокс-пилотом на пятидесяти клиентах: измеряют конверсию, средний чек и удержание, после чего уточняют ассортимент и условия. В юридических услугах пакет «юрфирма на аутсорсе» предлагается пяти клиентам на пробный месяц: оценивают востребованность и трудозатраты. Пилот позволяет выстроить услугу под реальные ожидания клиентов, не вкладываясь сразу в расширение штата. -::: diff --git a/pptx/content/slides/07d-spheres-7-8.md b/pptx/content/slides/07d-spheres-7-8.md deleted file mode 100644 index d498e7f..0000000 --- a/pptx/content/slides/07d-spheres-7-8.md +++ /dev/null @@ -1,21 +0,0 @@ -# Сферы 7–8: организация праздников и бытовые услуги - -::: callout "7. Организация праздников — онлайн-конструктор мероприятий" -- Новый товар: онлайн-конструктор мероприятий. -- Пилотный спринт: ==один сценарий== на пробной группе. -- Метрика Sprint Review: вовлечённость, повторные заказы, средняя стоимость. -- Решение: каталог успешных сценариев и автоматизация заказов. -- Особенность: непопулярные сценарии не масштабируются и не продвигаются. -::: - -::: callout "8. Бытовые услуги — подписка на уборку" -- Новый товар: подписка на уборку. -- Пилотный спринт: ==20 подписчиков== в одном районе. -- Метрика Sprint Review: удержание, число заказов, загрузка исполнителей. -- Решение: стандарты качества и масштабирование на другие районы. -- Особенность: логистика и качество отрабатываются в пилоте. -::: - -::: notes -Организация праздников и бытовые услуги. Онлайн-конструктор мероприятий тестируется на одной пробной группе: смотрят вовлечённость, повторные заказы и среднюю стоимость. Успешный сценарий становится основой каталога. Подписка на уборку стартует с двадцати подписчиков в одном районе: измеряют удержание, число заказов и загрузку исполнителей, после чего налаживают логистику и стандарты качества и выходят на другие районы. -::: diff --git a/pptx/content/slides/07e-spheres-9-10.md b/pptx/content/slides/07e-spheres-9-10.md deleted file mode 100644 index 9d9c9c2..0000000 --- a/pptx/content/slides/07e-spheres-9-10.md +++ /dev/null @@ -1,21 +0,0 @@ -# Сферы 9–10: IT-услуги и банки - -::: callout "9. IT-услуги — модуль SaaS-платформы" -- Новый товар: новый модуль SaaS-платформы. -- Пилотный спринт: ==бета на 10 клиентов==. -- Метрика Sprint Review: использование, частота ошибок, NPS. -- Решение: состав следующего релиза по обратной связи. -- Особенность: регулярные релизы — естественный режим гибкой разработки. -::: - -::: callout "10. Банковские услуги — вклад «Цель»" -- Новый товар: вклад «Цель» в мобильном приложении. -- Пилотный спринт: тест на ==ограниченной группе пользователей==. -- Метрика Sprint Review: доля открытий, средний срок, удержание. -- Решение: полное внедрение после согласования с подразделениями банка. -- Особенность: пилот проводится в контролируемых регулируемых условиях. -::: - -::: notes -Последние две сферы. В IT новый модуль SaaS-платформы выходит в бету на десять клиентов: измеряют использование, частоту ошибок и NPS, а обратная связь определяет состав следующего релиза — это естественный режим гибкой разработки. В банковских услугах вклад «Цель» тестируется на ограниченной группе пользователей приложения: оценивают долю открытий, срок и удержание. Даже в регулируемой сфере пилот в контролируемых условиях позволяет безопасно проверить спрос до полного внедрения. -::: diff --git a/pptx/content/slides/10-conclusion.md b/pptx/content/slides/10-conclusion.md deleted file mode 100644 index a052590..0000000 --- a/pptx/content/slides/10-conclusion.md +++ /dev/null @@ -1,17 +0,0 @@ -# Выводы - -- Agile/Scrum — ==универсальный метод== выведения товара на рынок -- Спринты заменяют один дорогой запуск серией дешёвых проверок -- Роли, артефакты и события делают процесс прозрачным и управляемым -- Метод работает везде, где есть клиент и обратная связь — от производства до банков -- Результат — снижение риска и стоимости ошибки при запуске новинки - -::: metrics -10 | сфер применения -30% | новинок выживают -4 | недели — длина спринта -::: - -::: notes -Таким образом, Agile и Scrum — универсальный метод выведения товара на рынок. Спринты заменяют один дорогой запуск серией дешёвых проверок. Роли, артефакты и события делают процесс прозрачным и управляемым. Метод работает везде, где есть клиент и обратная связь: от производства до банковских услуг. Результат — снижение риска и стоимости ошибки при запуске новинки. -::: diff --git a/pptx/content/slides/11-final.md b/pptx/content/slides/11-final.md deleted file mode 100644 index 561018e..0000000 --- a/pptx/content/slides/11-final.md +++ /dev/null @@ -1,9 +0,0 @@ -# Спасибо за внимание - -Степанов П.А., группа 6403-020302D - -Слушатель программы профессиональной переподготовки «Современные проектные технологии», ИОТ-трек «ДОП 11» - -::: notes -На этом мой доклад закончен, спасибо за внимание. Готов ответить на ваши вопросы. -::: diff --git a/pptx/content/slides/12-scrum-cycle.md b/pptx/content/slides/12-scrum-cycle.md deleted file mode 100644 index 394dfd5..0000000 --- a/pptx/content/slides/12-scrum-cycle.md +++ /dev/null @@ -1,17 +0,0 @@ -# Жизненный цикл Scrum - -::: image assets/scrum-cycle.puml side=left -Цикл Scrum: от Product Backlog до масштабирования товара -::: - -::: callout "Как замкнут цикл" side=right -- Product Backlog фиксирует требования к товару. -- Спринт длится 1–4 недели и завершается готовым ==инкрементом==. -- Sprint Review показывает инкремент рынку, ретроспектива улучшает процесс. -- Подтверждённый спрос ведёт к масштабированию, иначе цикл повторяется. -- Каждый виток спирали снижает неопределённость и стоимость ошибки. -::: - -::: notes -На этой схеме слева показан цикл Scrum. Из Product Backlog формируется план спринта. Спринт длится от одной до четырёх недель и завершается инкрементом — готовым пробным продуктом. На Sprint Review рынок даёт обратную связь, после чего команда проводит ретроспективу. Если спрос подтверждён, товар масштабируется; если нет — цикл повторяется с уточнёнными требованиями. Каждый виток снижает неопределённость. -::: diff --git a/pptx/package-lock.json b/pptx/package-lock.json index e101935..79f20ef 100644 --- a/pptx/package-lock.json +++ b/pptx/package-lock.json @@ -1,18 +1,18 @@ { - "name": "lab-gen-pptx", + "name": "ssau-generator-pptx", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "lab-gen-pptx", + "name": "ssau-generator-pptx", "version": "1.0.0", "dependencies": { "js-yaml": "^4.1.0", "pptxgenjs": "^3.12.0" }, "bin": { - "lab-gen-pptx": "src/cli.js" + "ssau-generator-pptx": "src/cli.js" } }, "node_modules/@types/node": { diff --git a/pptx/package.json b/pptx/package.json index 9e7f179..2d12b16 100644 --- a/pptx/package.json +++ b/pptx/package.json @@ -1,10 +1,10 @@ { - "name": "lab-gen-pptx", + "name": "ssau-generator-pptx", "version": "1.0.0", "private": true, - "description": "Генератор презентаций PPTX из Markdown по шаблону Самарского университета", + "description": "SSAU Generator PPTX — генератор презентаций PPTX из Markdown по шаблону Самарского университета", "bin": { - "lab-gen-pptx": "src/cli.js" + "ssau-generator-pptx": "src/cli.js" }, "main": "src/index.js", "scripts": { diff --git a/pptx/src/cli.js b/pptx/src/cli.js index 24f968b..cd84a03 100644 --- a/pptx/src/cli.js +++ b/pptx/src/cli.js @@ -1,8 +1,10 @@ #!/usr/bin/env node "use strict"; +const fs = require("fs"); const path = require("path"); const { build } = require("./build"); +const { ensureScaffold } = require("./scaffold"); function parseArgs(argv) { const options = { config: "config.yaml" }; @@ -20,6 +22,9 @@ function parseArgs(argv) { case "--check": options.check = true; break; + case "--init": + options.init = true; + break; case "--verbose": case "-v": options.verbose = true; @@ -43,15 +48,16 @@ function parseArgs(argv) { } function printHelp() { - console.log(`lab-gen-pptx — генератор презентаций PPTX из Markdown + console.log(`SSAU Generator PPTX — генератор презентаций PPTX из Markdown Использование: - lab-gen-pptx [config.yaml] [опции] + node pptx/src/cli.js [config.yaml] [опции] Опции: -c, --config путь к config.yaml (по умолчанию config.yaml) -o, --output переопределить имя выходного файла --check только проверить конфигурацию и ссылки + --init создать шаблон config.yaml/slides/assets и выйти -v, --verbose подробный вывод -h, --help показать справку --version показать версию @@ -68,6 +74,26 @@ async function main() { } const configPath = path.resolve(options.config); + + if (options.init || !fs.existsSync(configPath)) { + const targetDir = path.dirname(configPath); + try { + const created = await ensureScaffold(targetDir); + if (created.length) { + console.log("Создан шаблон генератора:"); + created.forEach((file) => console.log(" " + path.relative(targetDir, file))); + } else { + console.log("Файлы уже существуют, ничего не создано."); + } + console.log(""); + console.log("Отредактируйте config.yaml и файлы в slides/, затем запустите генератор снова."); + } catch (error) { + console.error(error.message); + process.exitCode = 1; + } + return undefined; + } + try { const result = await build({ config: configPath, check: options.check, output: options.output }); const { config, issues } = result; diff --git a/pptx/src/config.js b/pptx/src/config.js index 448a3d4..2f54763 100644 --- a/pptx/src/config.js +++ b/pptx/src/config.js @@ -24,9 +24,9 @@ const DEFAULTS = { line: "BFD3DD", }, backgrounds: { - title: "content/assets/title-bg.jpeg", - content: "content/assets/content-bg.jpg", - final: "content/assets/final-bg.jpeg", + title: "assets/title-bg.jpeg", + content: "assets/content-bg.jpg", + final: "assets/final-bg.jpeg", }, slideNumber: { show: true, @@ -110,7 +110,7 @@ const DEFAULTS = { timeoutMs: 30000, }, content: { - dir: "content", + dir: ".", }, slides: [], }; diff --git a/pptx/src/plantuml.js b/pptx/src/plantuml.js index 2d79d4b..19f246d 100644 --- a/pptx/src/plantuml.js +++ b/pptx/src/plantuml.js @@ -114,7 +114,7 @@ function cacheFileName(sourceBuffer, cfg) { } async function renderCached(sourceBuffer, cfg) { - const dir = cfg.cacheDir || path.join(os.tmpdir(), "lab-gen-pptx-plantuml"); + const dir = cfg.cacheDir || path.join(os.tmpdir(), "ssau-generator-pptx-plantuml"); const target = path.join(dir, cacheFileName(sourceBuffer, cfg)); if (cfg.cache && fs.existsSync(target)) { diff --git a/pptx/src/png.js b/pptx/src/png.js new file mode 100644 index 0000000..4e8d6f0 --- /dev/null +++ b/pptx/src/png.js @@ -0,0 +1,68 @@ +"use strict"; + +const zlib = require("zlib"); + +const CRC_TABLE = (() => { + const table = new Int32Array(256); + for (let n = 0; n < 256; n += 1) { + let c = n; + for (let k = 0; k < 8; k += 1) { + c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; + } + table[n] = c; + } + return table; +})(); + +function crc32(buffer) { + let crc = -1; + for (let i = 0; i < buffer.length; i += 1) { + crc = CRC_TABLE[(crc ^ buffer[i]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ -1) >>> 0; +} + +function chunk(type, data) { + const length = Buffer.alloc(4); + length.writeUInt32BE(data.length, 0); + const typeBuf = Buffer.from(type, "ascii"); + const crc = Buffer.alloc(4); + crc.writeUInt32BE(crc32(Buffer.concat([typeBuf, data])), 0); + return Buffer.concat([length, typeBuf, data, crc]); +} + +/** Кодирует PNG, получая цвет пикселя через getPixel(x, y) -> [r,g,b]. */ +function encodePng(width, height, getPixel) { + const signature = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); + const ihdr = Buffer.alloc(13); + ihdr.writeUInt32BE(width, 0); + ihdr.writeUInt32BE(height, 4); + ihdr[8] = 8; + ihdr[9] = 2; + + const rowLength = width * 3; + const raw = Buffer.alloc((rowLength + 1) * height); + for (let y = 0; y < height; y += 1) { + const offset = y * (rowLength + 1); + for (let x = 0; x < width; x += 1) { + const [r, g, b] = getPixel(x, y); + const px = offset + 1 + x * 3; + raw[px] = r; + raw[px + 1] = g; + raw[px + 2] = b; + } + } + + return Buffer.concat([ + signature, + chunk("IHDR", ihdr), + chunk("IDAT", zlib.deflateSync(raw, { level: 9 })), + chunk("IEND", Buffer.alloc(0)), + ]); +} + +function solidPng(width, height, color) { + return encodePng(width, height, () => color); +} + +module.exports = { solidPng, encodePng }; diff --git a/pptx/src/scaffold.js b/pptx/src/scaffold.js new file mode 100644 index 0000000..a160768 --- /dev/null +++ b/pptx/src/scaffold.js @@ -0,0 +1,115 @@ +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const yaml = require("js-yaml"); + +const { DEFAULTS, deepMerge } = require("./config"); +const { solidPng } = require("./png"); + +const CONFIG_HEADER = `# Конфигурация генератора SSAU Generator PPTX. +# Все относительные пути считаются от каталога этого файла. +# Любой ключ можно опустить — будет использовано значение по умолчанию. + +`; + +const SAMPLE = { + "slides/00-title.md": `# Название презентации + +## Подзаголовок +`, + "slides/01-content.md": `# Первый слайд + +- первый пункт списка; +- второй пункт списка: + + - вложенный пункт; + +Обычный абзац с **полужирным**, *курсивом* и ==выделением==. +`, + "slides/02-final.md": `# Спасибо за внимание +`, +}; + +// Цвета задников: [R, G, B]. +const BRAND = [27, 135, 201]; +const BACKGROUNDS = { + "title-bg.png": BRAND, + "content-bg.png": [255, 255, 255], + "final-bg.png": BRAND, +}; + +function isGeneratorDir(baseDir) { + const base = path.basename(baseDir).toLowerCase(); + return base === "docx" || base === "pptx"; +} + +/** + * Раскладка проекта: имя проекта = имя папки проекта, общие ресурсы в + * content/<проект>/assets/, результат — content/<проект>/<проект>.pptx. + */ +function projectLayout(baseDir) { + const isSub = isGeneratorDir(baseDir); + const projectDir = isSub ? path.dirname(baseDir) : baseDir; + const projectName = path.basename(projectDir) || "project"; + return { + projectDir, + projectName, + assetsRel: isSub ? "../assets" : "assets", + assetsDir: path.join(projectDir, "assets"), + outputRel: isSub ? `../${projectName}.pptx` : `${projectName}.pptx`, + }; +} + +function defaultConfigYaml(layout) { + const config = deepMerge(DEFAULTS, { + presentation: { output: layout.outputRel }, + theme: { + backgrounds: { + title: `${layout.assetsRel}/title-bg.png`, + content: `${layout.assetsRel}/content-bg.png`, + final: `${layout.assetsRel}/final-bg.png`, + }, + }, + content: { dir: "." }, + slides: [ + { type: "title", file: "slides/00-title.md" }, + { type: "content", file: "slides/01-content.md" }, + { type: "final", file: "slides/02-final.md" }, + ], + }); + return ( + CONFIG_HEADER + + yaml.dump(config, { noRefs: true, lineWidth: -1, sortKeys: false }) + ); +} + +/** + * Создаёт config.yaml, примеры слайдов и общие ресурсы проекта + * (content/<проект>/assets/), если их ещё нет. + */ +async function ensureScaffold(baseDir) { + const layout = projectLayout(baseDir); + const created = []; + const write = (target, content) => { + if (fs.existsSync(target)) return; + fs.mkdirSync(path.dirname(target), { recursive: true }); + if (content && typeof content === "object" && content.binary) { + fs.writeFileSync(target, content.binary); + } else { + fs.writeFileSync(target, content, "utf8"); + } + created.push(target); + }; + + write(path.join(baseDir, "config.yaml"), defaultConfigYaml(layout)); + for (const [name, content] of Object.entries(SAMPLE)) { + write(path.join(baseDir, name), content); + } + for (const [name, color] of Object.entries(BACKGROUNDS)) { + write(path.join(layout.assetsDir, name), { binary: solidPng(1920, 1080, color) }); + } + return created; +} + +module.exports = { projectLayout, defaultConfigYaml, ensureScaffold, SAMPLE }; diff --git a/video-script.md b/video-script.md deleted file mode 100644 index e4d9f8f..0000000 --- a/video-script.md +++ /dev/null @@ -1,98 +0,0 @@ -# Сценарий видеодоклада (≈5 минут) - -Докладчик: **Степанов П.А.**, группа **6403-020302D**, ИОТ-трек **«ДОП 11»**, -программа **«Современные проектные технологии»**. -Слайды — файл `pptx/presentation.pptx` (заметки докладчика дублируют этот текст). - ---- - -## 0:00–0:20. Приветствие (с паспортом) - -> Добрый день, уважаемые члены итоговой аттестационной комиссии. Меня зовут -> Степанов П.А. *(показать в камеру разворот паспорта)*, группа 6403-020302D, я -> являюсь слушателем программы профессиональной переподготовки «Современные -> проектные технологии», ИОТ-трек «ДОП 11». Разрешите представить решение -> итогового задания по теме «Современные проектные технологии». - -*(Слайд 1 — титульный.)* - -## 0:20–0:45. План доклада - -Сначала обосную выбор метода, затем покажу устройство методологии, проверку -спроса через спринты и применение в десяти сферах деятельности. *(Слайд 2.)* - -## 0:45–1:20. Постановка задачи - -Задача итогового задания — выбрать метод выведения нового товара на рынок и -обосновать его применимость в десяти сферах деятельности. Запуск новинки всегда -сопряжён с риском: до семи из десяти новых товаров не выживают на рынке. Поэтому -нужен управляемый и повторяемый процесс. В качестве такого метода я выбрал Agile -и его самую популярную методологию — Scrum. *(Слайд 3.)* - -## 1:20–2:30. Метод: Agile и Scrum - -Agile — это гибкий подход к управлению проектами, закреплённый в манифесте -2001 года. Scrum — самая распространённая Agile-методология. Работа разбивается на -короткие спринты длиной от одной до четырёх недель, каждый из которых завершается -готовым приростом продукта. *(Слайд 4.)* - -В Scrum три роли: Product Owner отвечает за ценность товара, Scrum Master убирает -препятствия, команда разработки создаёт продукт. Три артефакта — Product Backlog, -Sprint Backlog и Increment. Четыре события — планирование, ежедневная встреча, -обзор спринта и ретроспектива. *(Слайды 5–6.)* - -Весь цикл замкнут: из Product Backlog формируется спринт, который завершается -инкрементом; Sprint Review показывает результат рынку, а подтверждённый спрос ведёт -к масштабированию. *(Слайд 7.)* - -Ключевое преимущество: рынок проверяется дешёвым инкрементом — сначала минимальный -продукт, затем развитие по отклику реальных клиентов. *(Слайд 8.)* - -## 2:30–4:10. Применение в десяти сферах - -Покажу, что метод работает не только в IT. *(Слайд 9.)* В каждой сфере — свой -пилотный инкремент и своя метрика спринта. - -- **Производство** — линейка упаковки запускается пробной партией на одной линии; - метрики — себестоимость и доля брака. **Связь** — тариф «Умный дом» тестируется - на ста абонентах; смотрят подключения и отток. *(Слайд 10.)* -- **Транспорт** — каршеринг мини-фургонов стартует с пяти машин в одном районе; - метрики — загрузка и спрос. **Строительство** — сначала возводится один пилотный - модуль; оценивают затраты и сроки монтажа. *(Слайд 11.)* -- **Коммерция** — подписка на продуктовые наборы запускается бокс-пилотом на - пятидесяти клиентах; метрики — конверсия и удержание. **Юридические услуги** — - пакет «юрфирма на аутсорсе» предлагается пяти клиентам на пробный месяц. - *(Слайд 12.)* -- **Организация праздников** — онлайн-конструктор тестируется на одной группе по - вовлечённости и заказам. **Бытовые услуги** — подписка на уборку стартует с - двадцати подписчиков; важны удержание и загрузка. *(Слайд 13.)* -- **IT-услуги** — новый модуль SaaS выходит в бету на десять клиентов; метрики — - использование и NPS. **Банковские услуги** — вклад «Цель» тестируется на - ограниченной группе приложения. *(Слайд 14.)* - -Везде логика одна: ограниченный пробный продукт — замер метрики на Sprint Review — -масштабирование. - -## 4:10–4:45. Выводы - -Agile и Scrum — универсальный метод выведения товара на рынок. Спринты заменяют -один дорогой запуск серией дешёвых проверок. Метод работает везде, где есть клиент -и обратная связь: от производства до банковских услуг. Результат — снижение риска -и стоимости ошибки при запуске новинки. *(Слайд 15.)* - -## 4:45–5:00. Заключение - -> На этом мой доклад закончен, спасибо за внимание. - -*(Слайд 16.)* - ---- - -## Чек-лист записи - -- [ ] В начале доклада — **демонстрация паспорта** в камеру. -- [ ] В кадре одновременно видны **вы и презентация**. -- [ ] Приветствие, основная часть и заключение — по формулировкам выше. -- [ ] Формат файла — **mp4**, имя: `Видео защита Фамилия И.О.mp4`. -- [ ] Загрузить в облако: https://disk.ssau.ru/s/s8dSapsJ7bbn8yb -- [ ] PDF ответа: `Итоговое задание Фамилия И.О.pdf` — в «Материалы итогового задания».