@coopenomics/docs-factory 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -107
- package/dist/index.cjs +25 -15
- package/dist/index.mjs +25 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,117 +1,90 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
Фабрика документов
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
1
|
+
# @coopenomics/docs-factory
|
|
2
|
+
|
|
3
|
+
Фабрика документов цифрового кооператива. Собирает юридически значимые документы
|
|
4
|
+
по шаблонам из цепи и данным пайщиков: модель документа → HTML (Nunjucks) → PDF
|
|
5
|
+
(WeasyPrint 67). Хэш документа — SHA-256 PDF; повторная сборка по метаданным даёт
|
|
6
|
+
тот же документ байт в байт.
|
|
7
|
+
|
|
8
|
+
Пакет вынесен из монорепозитория `C9S/mono` 29.10.2026 (шаг 6а фабрики v2).
|
|
9
|
+
Прежнее имя `@coopenomics/factory` устарело.
|
|
10
|
+
|
|
11
|
+
## Что внутри
|
|
12
|
+
|
|
13
|
+
- **Сборщики всех видов документов** цифрового кооператива — 92 вида (`src/Actions`).
|
|
14
|
+
Сборщик — объявление: какие данные прочитать на блок документа и как собрать
|
|
15
|
+
из них модель (`defineBuilder`, `src/Builder`).
|
|
16
|
+
- **Версии сборщиков** `major.minor`. Версия пишется в `meta.builder` нового
|
|
17
|
+
документа; пересборка идёт ровно той версией, что записана в мете. Все версии
|
|
18
|
+
вида документа — в одном файле: `Factory` (1.0) и дописанные в конец
|
|
19
|
+
`Factory_1_1`, `Factory_2_0`. Выпущенная версия заморожена: исправление —
|
|
20
|
+
новый `minor` в конце файла.
|
|
21
|
+
- **Шаблоны и реестр шаблонов** (`src/Templates`) с номерами редакций; ключ
|
|
22
|
+
`x-builder` в схеме редакции объявляет, под какой `major` сборщика она написана.
|
|
23
|
+
- **Порт хранилища** `IFactoryStorage` и реализации: PostgreSQL
|
|
24
|
+
(`PostgresFactoryStorage`, Kysely) и память (`MemoryFactoryStorage`).
|
|
25
|
+
- **Порт данных цепи** `IChainDataSource`: шаблоны, таблицы и действия на блок.
|
|
14
26
|
|
|
15
27
|
## Установка
|
|
16
28
|
|
|
17
|
-
Компонент является частью монорепозитория. Установка зависимостей из корня проекта:
|
|
18
|
-
|
|
19
29
|
```bash
|
|
20
|
-
pnpm
|
|
30
|
+
pnpm add @coopenomics/docs-factory cooptypes
|
|
21
31
|
```
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
pnpm install --filter @coopenomics/factory
|
|
27
|
-
```
|
|
33
|
+
`cooptypes` — зависимость приложения (`peerDependencies`): фабрика берёт тот
|
|
34
|
+
выпуск, что стоит у приложения.
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
Для PDF нужен WeasyPrint 67 в `/venv/bin/python3` и системный шрифт Arial —
|
|
37
|
+
как в образе контроллера (`components/controller/Dockerfile` в `C9S/mono`).
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
## Использование
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
```ts
|
|
42
|
+
import { Generator, PostgresFactoryStorage } from '@coopenomics/docs-factory'
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| `build` | `pnpm run build` | Сборка библиотеки (unbuild) |
|
|
38
|
-
| `dev` | `pnpm run dev` | Режим разработки с автопересборкой (nodemon) |
|
|
39
|
-
| `test` | `pnpm run test` | Запуск тестов (Vitest) |
|
|
40
|
-
| `lint` | `pnpm run lint` | Проверка кода (ESLint) |
|
|
41
|
-
| `typecheck` | `pnpm run typecheck` | Проверка типов TypeScript |
|
|
42
|
-
| `setup-indexes` | `pnpm run setup-indexes` | Настройка индексов MongoDB |
|
|
44
|
+
const generator = new Generator(chainDataSource) // реализация IChainDataSource
|
|
45
|
+
await generator.connect(new PostgresFactoryStorage({ host, port, user, password, database }))
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
// Новая сборка: версия сборщика — по объявлению действующей редакции шаблона
|
|
48
|
+
const document = await generator.generate({ registry_id: 1, coopname: 'voskhod', username: 'ant', lang: 'ru' })
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
pnpm run dev:lib # Режим разработки factory + cooptypes
|
|
49
|
-
pnpm run test:component # Компонентные тесты factory
|
|
50
|
+
// Пересборка по метаданным подписанного документа — тем же сборщиком
|
|
51
|
+
const same = await generator.generate({ ...document.meta }, { skip_save: true })
|
|
50
52
|
```
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
Таблицы хранилища на узле создаёт миграция контроллера; отдельному приложению —
|
|
55
|
+
`await storage.ensureSchema()`.
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
## Разработка
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
Тесты и эталоны запускаются только в CI (workflow `Factory`, `.github/workflows/factory.yml`)
|
|
60
|
+
на каждый пуш. Локально — сборка и проверки сборщиков:
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
| Команда | Что делает |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `pnpm build` | сборка (unbuild) с проверкой типов |
|
|
65
|
+
| `pnpm lint` | ESLint |
|
|
66
|
+
| `pnpm check` | полнота экспорта сборщиков, чтения на блок, заморозка версий |
|
|
67
|
+
| `node scripts/x-builder-check.mjs` | `x-builder` не меняется внутри редакции (после `pnpm build`) |
|
|
68
|
+
| `node scripts/golden-coverage.mjs` | у каждого вида документа есть эталон |
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
Эталоны — `test/golden/<номер>/<случай>.{html,meta.json,pdf.sha256}`. Пересоздать —
|
|
71
|
+
пуш в ветку `ci/update`, забрать артефакт `factory-golden`, закоммитить; только
|
|
72
|
+
при осознанной смене вывода. Правила для сборщиков — `CLAUDE.md`.
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Тестовый набор покрывает генерацию документов различных типов. Тесты требуют запущенный MongoDB и используют таймаут 240 секунд.
|
|
68
|
-
|
|
69
|
-
Файлы тестов:
|
|
74
|
+
Совместная правка с монорепозиторием: в `C9S/mono` — `pnpm factory:link`
|
|
75
|
+
(подключает этот чекаут, ожидается в `~/docs-factory`) и `pnpm factory:unlink`.
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|------|----------|
|
|
73
|
-
| `test/index.test.ts` | Основные тесты генерации документов |
|
|
74
|
-
| `test/wallet.test.ts` | Тесты документов кошелька |
|
|
75
|
-
| `test/meet.test.ts` | Тесты документов собраний |
|
|
76
|
-
| `test/blagorost.test.ts` | Тесты документов программы «Благорост» |
|
|
77
|
-
| `test/market.test.ts` | Тесты документов маркетплейса |
|
|
78
|
-
| `test/search.test.ts` | Тесты поиска документов |
|
|
79
|
-
| `test/udata.test.ts` | Тесты пользовательских данных |
|
|
80
|
-
| `test/documents-1000-plus.test.ts` | Тесты документов с registry_id > 1000 |
|
|
77
|
+
## Выпуск
|
|
81
78
|
|
|
82
|
-
|
|
79
|
+
1. Поднять `version` в `package.json` (семантическая версия), коммит в `main`.
|
|
80
|
+
2. Тег `vX.Y.Z` (предварительный — `vX.Y.Z-dev.N`) в `C9S/docs-factory`.
|
|
81
|
+
3. Workflow `Release`: проверки Factory → сверка тега с версией → публикация в npm
|
|
82
|
+
(предварительная — с меткой `next`) → робот открывает PR в `C9S/mono` → `dev`
|
|
83
|
+
с новой точной версией во всех `package.json` и `pnpm-lock.yaml`.
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
├── config.ts # Конфигурация подключений
|
|
88
|
-
├── Actions/ # Генераторы документов (по registry_id)
|
|
89
|
-
│ ├── 1.WalletAgreement.ts
|
|
90
|
-
│ ├── 100.ParticipantApplication.ts
|
|
91
|
-
│ ├── 300.AnnualGeneralMeetingAgenda.ts
|
|
92
|
-
│ ├── 600.FreeDecision.ts
|
|
93
|
-
│ ├── 1001.GenerationContract.ts
|
|
94
|
-
│ └── ... # Более 60 шаблонов
|
|
95
|
-
├── Factory/ # Ядро фабрики документов
|
|
96
|
-
├── Models/ # Модели данных MongoDB
|
|
97
|
-
│ ├── Cooperative.ts
|
|
98
|
-
│ ├── Individual.ts
|
|
99
|
-
│ ├── Organization.ts
|
|
100
|
-
│ ├── Document.ts
|
|
101
|
-
│ └── ...
|
|
102
|
-
└── templates/ # HTML-шаблоны (Nunjucks/Handlebars)
|
|
103
|
-
test/ # Тесты (Vitest)
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Процесс генерации документа
|
|
107
|
-
|
|
108
|
-
1. Загрузка шаблона и JSON Schema из блокчейна
|
|
109
|
-
2. Получение приватных данных из хранилища (MongoDB)
|
|
110
|
-
3. Валидация данных по JSON Schema (Ajv)
|
|
111
|
-
4. Конструирование контекста для шаблона
|
|
112
|
-
5. Рендеринг HTML из Nunjucks/Handlebars-шаблона
|
|
113
|
-
6. Подпись хеша документа EOSIO-ключом
|
|
114
|
-
7. Генерация PDF через WeasyPrint
|
|
85
|
+
Монорепозиторий поднимает версию только этим PR: гейт `pnpm check` держит
|
|
86
|
+
точную и одну версию, контроллер при старте сверяет установленную фабрику с
|
|
87
|
+
объявленной.
|
|
115
88
|
|
|
116
89
|
## Приватные данные документа: `doc_data`
|
|
117
90
|
|
|
@@ -121,7 +94,7 @@ test/ # Тесты (Vitest)
|
|
|
121
94
|
|
|
122
95
|
1. Контроллер собирает приватный payload и вызывает `generator.saveDocData(payload, registry_id)` — возвращается `{ hash }` (sha256, идемпотентный).
|
|
123
96
|
2. `hash` передаётся on-chain в Action под зарезервированным именем `doc_data_hash`.
|
|
124
|
-
3. При
|
|
97
|
+
3. При сборке и пересборке фабрика подгружает payload из хранилища (`getDocData(hash)`) и подставляет в модель документа как `doc_data`.
|
|
125
98
|
4. Шаблон документа использует приватные поля как `{{ doc_data.<field> }}`.
|
|
126
99
|
|
|
127
100
|
### Пример
|
|
@@ -146,14 +119,17 @@ await generator.generate({
|
|
|
146
119
|
})
|
|
147
120
|
```
|
|
148
121
|
|
|
149
|
-
|
|
122
|
+
Сборщик (`src/Actions/1103.MarketplaceTransportNote.ts`) объявляет чтение, каркас его выполняет:
|
|
150
123
|
|
|
151
124
|
```ts
|
|
152
|
-
|
|
153
|
-
|
|
125
|
+
reads: ({ data, f }) => ({
|
|
126
|
+
docData: () => f.loadDocData<TransportNoteDocData>(data),
|
|
127
|
+
// …
|
|
128
|
+
}),
|
|
129
|
+
assemble: ({ meta, reads: { docData } }) => ({ meta, doc_data: docData, /* … */ }),
|
|
154
130
|
```
|
|
155
131
|
|
|
156
|
-
Шаблон (`Templates/1103.MarketplaceTransportNote
|
|
132
|
+
Шаблон (`src/Templates/1103.MarketplaceTransportNote.ts`):
|
|
157
133
|
|
|
158
134
|
```html
|
|
159
135
|
<tr><th>Экспедитор</th><td>{{ doc_data.expeditor_full_name }}</td></tr>
|
|
@@ -174,22 +150,13 @@ const combinedData = { ...base, doc_data }
|
|
|
174
150
|
|
|
175
151
|
### Graceful degradation
|
|
176
152
|
|
|
177
|
-
Если
|
|
153
|
+
Если приватные данные удалены (например, по запросу пайщика), документ остаётся **верифицируемым по хэшу подписи** (хэш зафиксирован on-chain), но не регенерируется. Это явное архитектурное решение: ценность блокчейн-подписи сохраняется; восстановление PDF — обратимо deprecated.
|
|
178
154
|
|
|
179
155
|
### Когда применять
|
|
180
156
|
|
|
181
157
|
- **Новые документы** с персональными данными — сразу через `doc_data`.
|
|
182
158
|
- **Существующие документы** (700-1099, 300-304 и т.д.) — остаются без изменений. Паттерн прогрессивный, переводить старые документы при отсутствии необходимости не нужно.
|
|
183
159
|
|
|
184
|
-
## Ключевые зависимости
|
|
185
|
-
|
|
186
|
-
- **nunjucks / handlebars** — шаблонизаторы
|
|
187
|
-
- **ajv** — валидация JSON Schema
|
|
188
|
-
- **mongodb** — хранилище данных
|
|
189
|
-
- **eosjs-ecc** — криптографические операции EOSIO
|
|
190
|
-
- **pdf-lib** — работа с PDF
|
|
191
|
-
- **unbuild** — сборка библиотеки
|
|
192
|
-
|
|
193
160
|
## Лицензия
|
|
194
161
|
|
|
195
162
|
[BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru)
|
package/dist/index.cjs
CHANGED
|
@@ -5045,7 +5045,7 @@ function latestMinorOf(versions, major) {
|
|
|
5045
5045
|
|
|
5046
5046
|
const name = "@coopenomics/docs-factory";
|
|
5047
5047
|
const type = "module";
|
|
5048
|
-
const version = "1.
|
|
5048
|
+
const version = "1.1.0";
|
|
5049
5049
|
const description = "Фабрика документов цифрового кооператива: сборка документов по шаблонам, сборщики всех видов документов, версии сборщиков";
|
|
5050
5050
|
const author = "Alex Ant <chairman.voskhod@gmail.com>";
|
|
5051
5051
|
const license = "MIT";
|
|
@@ -9984,12 +9984,16 @@ const Actions = {
|
|
|
9984
9984
|
WalletAgreement: _1_WalletAgreement
|
|
9985
9985
|
};
|
|
9986
9986
|
|
|
9987
|
+
const BUILDER_EXPORT = /^Factory(_\d+_\d+)?$/;
|
|
9987
9988
|
function isBuilderModule(value) {
|
|
9988
9989
|
if (!value || typeof value !== "object")
|
|
9989
9990
|
return false;
|
|
9990
9991
|
const m = value;
|
|
9991
9992
|
return typeof m.Factory === "function" && typeof m.Template?.registry_id === "number";
|
|
9992
9993
|
}
|
|
9994
|
+
function builderExports(module) {
|
|
9995
|
+
return Object.entries(module).filter(([key, value]) => BUILDER_EXPORT.test(key) && typeof value === "function");
|
|
9996
|
+
}
|
|
9993
9997
|
function buildFactories(modules, storage) {
|
|
9994
9998
|
const builders = {};
|
|
9995
9999
|
const problems = [];
|
|
@@ -9999,21 +10003,27 @@ function buildFactories(modules, storage) {
|
|
|
9999
10003
|
continue;
|
|
10000
10004
|
}
|
|
10001
10005
|
const id = module.Template.registry_id;
|
|
10002
|
-
const
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10006
|
+
for (const [exportName, Builder] of builderExports(module)) {
|
|
10007
|
+
const where = `${name}.${exportName}`;
|
|
10008
|
+
const factory = new Builder(storage);
|
|
10009
|
+
const spec = factory.spec;
|
|
10010
|
+
if (spec?.registry_id !== void 0 && spec.registry_id !== id)
|
|
10011
|
+
problems.push(`${where}: \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${spec.registry_id} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442 \u0441 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u0430 ${id}`);
|
|
10012
|
+
const version = spec?.version ?? FIRST_BUILDER_VERSION;
|
|
10013
|
+
if (!isBuilderVersion(version)) {
|
|
10014
|
+
problems.push(`${where}: \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${JSON.stringify(version)} \u043D\u0435 \u0432 \u0432\u0438\u0434\u0435 major.minor`);
|
|
10015
|
+
continue;
|
|
10016
|
+
}
|
|
10017
|
+
const expected = exportName === "Factory" ? FIRST_BUILDER_VERSION : exportName.slice("Factory_".length).replace("_", ".");
|
|
10018
|
+
if (version !== expected)
|
|
10019
|
+
problems.push(`${where}: \u044D\u043A\u0441\u043F\u043E\u0440\u0442 ${exportName} \u043E\u0431\u044A\u044F\u0432\u043B\u044F\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u044E ${version}, \u043F\u043E \u0438\u043C\u0435\u043D\u0438 \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${expected}`);
|
|
10020
|
+
const set = builders[id] ?? (builders[id] = /* @__PURE__ */ new Map());
|
|
10021
|
+
if (set.has(version)) {
|
|
10022
|
+
problems.push(`${where}: \u0432\u0435\u0440\u0441\u0438\u044F ${version} \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${id} \u0443\u0436\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0430`);
|
|
10023
|
+
continue;
|
|
10024
|
+
}
|
|
10025
|
+
set.set(version, factory);
|
|
10015
10026
|
}
|
|
10016
|
-
set.set(version, factory);
|
|
10017
10027
|
}
|
|
10018
10028
|
const templateIds = Object.keys(Registry).map(Number);
|
|
10019
10029
|
for (const id of templateIds) {
|
package/dist/index.mjs
CHANGED
|
@@ -5030,7 +5030,7 @@ function latestMinorOf(versions, major) {
|
|
|
5030
5030
|
|
|
5031
5031
|
const name = "@coopenomics/docs-factory";
|
|
5032
5032
|
const type = "module";
|
|
5033
|
-
const version = "1.
|
|
5033
|
+
const version = "1.1.0";
|
|
5034
5034
|
const description = "Фабрика документов цифрового кооператива: сборка документов по шаблонам, сборщики всех видов документов, версии сборщиков";
|
|
5035
5035
|
const author = "Alex Ant <chairman.voskhod@gmail.com>";
|
|
5036
5036
|
const license = "MIT";
|
|
@@ -9969,12 +9969,16 @@ const Actions = {
|
|
|
9969
9969
|
WalletAgreement: _1_WalletAgreement
|
|
9970
9970
|
};
|
|
9971
9971
|
|
|
9972
|
+
const BUILDER_EXPORT = /^Factory(_\d+_\d+)?$/;
|
|
9972
9973
|
function isBuilderModule(value) {
|
|
9973
9974
|
if (!value || typeof value !== "object")
|
|
9974
9975
|
return false;
|
|
9975
9976
|
const m = value;
|
|
9976
9977
|
return typeof m.Factory === "function" && typeof m.Template?.registry_id === "number";
|
|
9977
9978
|
}
|
|
9979
|
+
function builderExports(module) {
|
|
9980
|
+
return Object.entries(module).filter(([key, value]) => BUILDER_EXPORT.test(key) && typeof value === "function");
|
|
9981
|
+
}
|
|
9978
9982
|
function buildFactories(modules, storage) {
|
|
9979
9983
|
const builders = {};
|
|
9980
9984
|
const problems = [];
|
|
@@ -9984,21 +9988,27 @@ function buildFactories(modules, storage) {
|
|
|
9984
9988
|
continue;
|
|
9985
9989
|
}
|
|
9986
9990
|
const id = module.Template.registry_id;
|
|
9987
|
-
const
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
9991
|
+
for (const [exportName, Builder] of builderExports(module)) {
|
|
9992
|
+
const where = `${name}.${exportName}`;
|
|
9993
|
+
const factory = new Builder(storage);
|
|
9994
|
+
const spec = factory.spec;
|
|
9995
|
+
if (spec?.registry_id !== void 0 && spec.registry_id !== id)
|
|
9996
|
+
problems.push(`${where}: \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${spec.registry_id} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442 \u0441 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0448\u0430\u0431\u043B\u043E\u043D\u0430 ${id}`);
|
|
9997
|
+
const version = spec?.version ?? FIRST_BUILDER_VERSION;
|
|
9998
|
+
if (!isBuilderVersion(version)) {
|
|
9999
|
+
problems.push(`${where}: \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${JSON.stringify(version)} \u043D\u0435 \u0432 \u0432\u0438\u0434\u0435 major.minor`);
|
|
10000
|
+
continue;
|
|
10001
|
+
}
|
|
10002
|
+
const expected = exportName === "Factory" ? FIRST_BUILDER_VERSION : exportName.slice("Factory_".length).replace("_", ".");
|
|
10003
|
+
if (version !== expected)
|
|
10004
|
+
problems.push(`${where}: \u044D\u043A\u0441\u043F\u043E\u0440\u0442 ${exportName} \u043E\u0431\u044A\u044F\u0432\u043B\u044F\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u044E ${version}, \u043F\u043E \u0438\u043C\u0435\u043D\u0438 \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${expected}`);
|
|
10005
|
+
const set = builders[id] ?? (builders[id] = /* @__PURE__ */ new Map());
|
|
10006
|
+
if (set.has(version)) {
|
|
10007
|
+
problems.push(`${where}: \u0432\u0435\u0440\u0441\u0438\u044F ${version} \u0441\u0431\u043E\u0440\u0449\u0438\u043A\u0430 ${id} \u0443\u0436\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0430`);
|
|
10008
|
+
continue;
|
|
10009
|
+
}
|
|
10010
|
+
set.set(version, factory);
|
|
10000
10011
|
}
|
|
10001
|
-
set.set(version, factory);
|
|
10002
10012
|
}
|
|
10003
10013
|
const templateIds = Object.keys(Registry).map(Number);
|
|
10004
10014
|
for (const id of templateIds) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopenomics/docs-factory",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"description": "Фабрика документов цифрового кооператива: сборка документов по шаблонам, сборщики всех видов документов, версии сборщиков",
|
|
6
6
|
"author": "Alex Ant <chairman.voskhod@gmail.com>",
|
|
7
7
|
"license": "MIT",
|