@nan0web/release 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,50 +1,49 @@
1
1
  {
2
- "name": "@nan0web/release",
3
- "version": "1.0.2",
4
- "description": "Project Management as Code, Git-Native, GPG-Signed, Test-Driven",
5
- "main": "src/index.js",
6
- "types": "types/index.d.ts",
7
- "type": "module",
8
- "bin": {
9
- "nan0release": "./bin/nan0release.js",
10
- "release": "./bin/nan0release.js"
11
- },
12
- "scripts": {
13
- "build": "tsc",
14
- "clean": "rm -rf .cache/ && rm -rf dist/",
15
- "clean:modules": "rm -rf node_modules",
16
- "test": "node --test \"src/**/*.test.js\"",
17
- "test1": "node --test \"src/**/*.test.js\" | nan0test parse --fail",
18
- "test:docs": "node --test \"src/README.md.js\"",
19
- "test:release": "node --test \"releases/**/*.test.js\"",
20
- "test:coverage": "node --experimental-test-coverage --test-coverage-include=\"src/**/*.js\" --test-coverage-exclude=\"src/**/*.test.js\" --test \"src/**/*.test.js\"",
21
- "test:coverage:collect": "nan0test coverage",
22
- "test:status": "nan0test status",
23
- "test:all": "npm run test && npm run test:docs && npm run build && npm run knip",
24
- "test:all1": "npm run test && npm run test:docs && npm run test:status && npm run build",
25
- "knip": "knip --production",
26
- "release": "node ./bin/nan0release.js publish",
27
- "precommit": "npm test",
28
- "prepush": "npm test",
29
- "prepare": "husky",
30
- "playground": "node playground/main.js"
31
- },
32
- "dependencies": {
33
- "@nan0web/changelog": "*",
34
- "@nan0web/co": "*",
35
- "@nan0web/db": "*",
36
- "@nan0web/db-fs": "*",
37
- "@nan0web/log": "*",
38
- "@nan0web/markdown": "*",
39
- "@nan0web/types": "*",
40
- "@nan0web/ui": "*",
41
- "@nan0web/ui-cli": "*",
42
- "@nan0web/verse": "*",
43
- "supports-color": "^10.2.2"
44
- },
45
- "devDependencies": {
46
- "@nan0web/test": "*",
47
- "husky": "^9.1.7",
48
- "knip": "^5.85.0"
49
- }
50
- }
2
+ "name": "@nan0web/release",
3
+ "version": "1.0.3",
4
+ "description": "Project Management as Code, Git-Native, GPG-Signed, Test-Driven",
5
+ "main": "src/index.js",
6
+ "types": "types/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "nan0release": "./bin/nan0release.js",
10
+ "release": "./bin/nan0release.js"
11
+ },
12
+ "dependencies": {
13
+ "@nan0web/changelog": "^1.0.0",
14
+ "@nan0web/co": "^2.0.0",
15
+ "@nan0web/db": "^1.3.3",
16
+ "@nan0web/db-fs": "^1.1.4",
17
+ "@nan0web/log": "^1.1.1",
18
+ "@nan0web/markdown": "^1.0.2",
19
+ "@nan0web/types": "^1.4.0",
20
+ "@nan0web/ui": "^1.8.0",
21
+ "@nan0web/ui-cli": "^2.9.0",
22
+ "@nan0web/verse": "^1.0.0",
23
+ "supports-color": "^10.2.2"
24
+ },
25
+ "devDependencies": {
26
+ "@nan0web/test": "^1.1.3",
27
+ "husky": "^9.1.7",
28
+ "knip": "^5.86.0"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc",
32
+ "clean": "rm -rf .cache/ && rm -rf dist/",
33
+ "clean:modules": "rm -rf node_modules",
34
+ "test": "node --test \"src/**/*.test.js\"",
35
+ "test1": "node --test \"src/**/*.test.js\" | nan0test parse --fail",
36
+ "test:docs": "node --test \"src/README.md.js\"",
37
+ "test:release": "node --test \"releases/**/*.test.js\"",
38
+ "test:coverage": "node --experimental-test-coverage --test-coverage-include=\"src/**/*.js\" --test-coverage-exclude=\"src/**/*.test.js\" --test \"src/**/*.test.js\"",
39
+ "test:coverage:collect": "nan0test coverage",
40
+ "test:status": "nan0test status",
41
+ "test:all": "npm run test && npm run test:docs && npm run build && npm run knip",
42
+ "test:all1": "npm run test && npm run test:docs && npm run test:status && npm run build",
43
+ "knip": "knip --production",
44
+ "release": "node ./bin/nan0release.js publish",
45
+ "precommit": "npm test",
46
+ "prepush": "npm test",
47
+ "playground": "node playground/main.js"
48
+ }
49
+ }
package/project.yaml ADDED
@@ -0,0 +1,79 @@
1
+ ---
2
+ metadata:
3
+ description: ""
4
+ tags: []
5
+ status: planned
6
+ locale: uk
7
+ sections:
8
+ - title: "🧭 Фаза 1: Філософія та Абстракція (The Seed)"
9
+ content:
10
+ - "**Місія:** Управління проєктами як код (Project Management as Code). Ми відмовляємось від зовнішніх трекерів задач (Jira, Trello). Проєкт — це набір технічних **контрактів**, які проходять шлях від наміру до імплементації, забезпечуючи реальний статус прогресу автоматично."
11
+ - "**Базова Абстракція:** Пакет відповідає за логіку та CLI, яка читає Markdown, генерує контракти (`.spec.js`), а потім закриває їх як тести (`.test.js`) з подальшою вічною регресією (тести копіюються в кодову базу)."
12
+ - "**Глосарій:**"
13
+ - "- **Release Document**: `release.md` з ТЗ та відомостями про команду."
14
+ - "- **WIP Контракт**: `*.spec.js`, який падає/у стані `todo`, доки задачу не взяли і не зробили. Оновлює прогрес автоматично при виконанні."
15
+ - "- **Закритий Контракт**: `*.test.js` (результат команди `close`). Він стає законом і гарантує регресію через `pnpm test`."
16
+ - "---"
17
+ tasks: []
18
+ - title: "📐 Фаза 2: Доменне Моделювання (Data-Driven Models)"
19
+ content:
20
+ - "Сутності і моделі, які керують процесом релізу, не мають жорсткої прив'язки до вебу, але описуються як чисті об'єкти:"
21
+ - "- `Release`: Координує стан (версія, час початку, час завершення)."
22
+ - "- `ReleaseDocument`: Структурує Markdown у модель (дістає задачі)."
23
+ - "- `Person`: Типізована перевірка того, хто схвалив дії (через GPG або JSON підпис)."
24
+ - "- `Scanner`: Абстракція доступу до файлової системи (`releases/`)."
25
+ - "Статуси відстежуються динамічно через статус тестів: `it.todo` -> `it.skip` -> `it()`."
26
+ - "---"
27
+ tasks: []
28
+ - title: "🛠 Фаза 3: Верифікація Логіки (CLI-First)"
29
+ content:
30
+ - "Уся бізнес-логіка @nan0web/release 100% покривається Unit-тестами та CLI командами. Жодного веб-коду. Використовуємо Message-based архітектуру `@nan0web/ui-cli`."
31
+ - "1. **Команди CLI (`bin/nan0release.js`):**"
32
+ - "- `deps`, `publish` (реалізовані)."
33
+ - "- Заплановані (`init`, `spec`, `close`, `status`) інкапсулюють керування `Scanner` та `Release` моделями."
34
+ - "2. **Contract Lifecycle (Автоматизація прогресу):**"
35
+ - "- На старті `.spec.js` мають `it.todo()` → задача в беклозі."
36
+ - "- Коли розробник бере задачу → генерує логіку, змінює на `it()`. При коміті реальний прогрес проекту видно \"зеленим\"."
37
+ - "- `nan0release close` перейменовує `spec → test` і переносить його в `src/releases/` для 100% автоматичної регресії."
38
+ - "---"
39
+ tasks: []
40
+ - title: "🪐 Фаза 4: Sovereign Workbench (The Master IDE)"
41
+ content:
42
+ - "_(Для цього пакету застосовується опціонально, оскільки тут CLI-First)_"
43
+ - "Пакет `release` є постачальником даних для інших Sandbox-середовищ, де може виводитись:"
44
+ - "- Dashboard релізу (таблиці статусів `wip/closed/mixed`)."
45
+ - "- Для цього ми генеруємо `.datasets/README.dataset.jsonl` за допомогою `test:docs`, щоб створювати машиночитабельні знання для LLM-агентів для донавчання або можна користуватись README.md як індексу у реальному часі."
46
+ - "---"
47
+ tasks: []
48
+ - title: "🎨 Фаза 5: Тематизація та Інтерфейс (Theming)"
49
+ content:
50
+ - "_(Може застосовуватися при запуску HTML звітів про реліз або Dashboard)_"
51
+ - "Логіка `release UI` (якщо така з'явиться у додатку `@nan0web/release.app`), буде імпортувати компоненти з `@nan0web/ui-lit` зі строгим слідуванням CSS-змінним (напр. `--co` для кольорів бренду) без створення кастомних стилів."
52
+ - "---"
53
+ tasks: []
54
+ - title: "🏁 Чек-лист готовності пакету (Definition of Done)"
55
+ content: []
56
+ tasks:
57
+ - title: "General"
58
+ content: []
59
+ items:
60
+ - text: "Визначена місія та філософія у `system.md` та `project.md`."
61
+ completed: true
62
+ - text: "Робота з Markdown-нотатками та базова доменна логіка (`Scanner`, `Release`)."
63
+ completed: true
64
+ - text: "Атомарна операція закриття контрактів (`Scanner.close()`)."
65
+ completed: true
66
+ - text: "Всі існуючі специфікації проходять через CLI та `node:test` (22/24 pass, 2 skip)."
67
+ completed: true
68
+ - text: "Прогрес автоматизується зміною статусу `spec.js` (todo/skip/pass)."
69
+ completed: true
70
+ - text: "Усі CLI сценарії для AGRP (spec, close, init, status) завершені."
71
+ completed: false
72
+ - text: "Створені API-ендпоінти для відображення релізного прогресу у React-Dashboard."
73
+ completed: false
74
+ total: 7
75
+ completed: 5
76
+ stats:
77
+ totalTasks: 7
78
+ completedTasks: 5
79
+ progress: 71
@@ -0,0 +1,465 @@
1
+ import { describe, it, before, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { readFile } from 'node:fs/promises'
4
+ import FS from '@nan0web/db-fs'
5
+ import { NoConsole } from '@nan0web/log'
6
+ import { DatasetParser, DocsParser, runSpawn } from '@nan0web/test'
7
+ import ReleaseCLi from './ui/cli/ReleaseCLi.js'
8
+ import Release from './Release.js'
9
+ import ReleaseDocument from './Release/Document.js'
10
+ import Person from './Release/Person.js'
11
+ import {
12
+ ProjectManagement,
13
+ ReleaseManager,
14
+ TaskTestSuite,
15
+ ChangelogTaskManager,
16
+ } from './architecture/ProjectManagementAsCode.js'
17
+
18
+ const fs = new FS()
19
+ let pkg
20
+
21
+ // Load package.json once before tests
22
+ before(async () => {
23
+ const doc = await fs.loadDocument('package.json', {})
24
+ pkg = doc || {}
25
+ })
26
+
27
+ let console = new NoConsole()
28
+
29
+ beforeEach(() => {
30
+ console = new NoConsole()
31
+ })
32
+
33
+ /**
34
+ * Core test suite that also serves as the source for README generation.
35
+ *
36
+ * The block comments inside each `it` block are extracted to build
37
+ * the final `README.md`. Keeping the comments here ensures the
38
+ * documentation stays close to the code.
39
+ */
40
+ function testRender() {
41
+ /**
42
+ * @docs
43
+ * # @nan0web/release
44
+ *
45
+ * <!-- %PACKAGE_STATUS% -->
46
+ *
47
+ * Project management as code, Git-native, GPG-signed, and test-driven.
48
+ *
49
+ * Unlike traditional project tools that require constant syncing or manual updates,
50
+ * `@nan0web/release` enforces project structure where:
51
+ * - Tasks are represented as tests in `.test.js` files.
52
+ * - Status is tracked via test outcomes.
53
+ * - Team roles and approvals are stored in structured files.
54
+ * - All changes are signed, versioned, and composable.
55
+ *
56
+ * This ensures:
57
+ * - Clear, automatable project tracking.
58
+ * - Immutable release notes and retro reflections.
59
+ * - Zero ambiguity – tasks don't exist unless tested.
60
+ *
61
+ * ## Installation
62
+ */
63
+ it('How to install with pnpm?', () => {
64
+ /**
65
+ * ```bash
66
+ * pnpm add @nan0web/release
67
+ * ```
68
+ */
69
+ assert.equal(pkg.name, '@nan0web/release')
70
+ })
71
+ /**
72
+ * @docs
73
+ */
74
+ it('How to install with npm?', () => {
75
+ /**
76
+ * ```bash
77
+ * npm install @nan0web/release
78
+ * ```
79
+ */
80
+ assert.equal(pkg.name, '@nan0web/release')
81
+ })
82
+ /**
83
+ * @docs
84
+ */
85
+ it('How to install with yarn?', () => {
86
+ /**
87
+ * ```bash
88
+ * yarn add @nan0web/release
89
+ * ```
90
+ */
91
+ assert.equal(pkg.name, '@nan0web/release')
92
+ })
93
+
94
+ /**
95
+ * @docs
96
+ * ## CLI Usage
97
+ *
98
+ * Start by initializing a new release:
99
+ */
100
+ it('How to initialize a new release version?', () => {
101
+ /**
102
+ * ```bash
103
+ * release init v1.0.0
104
+ * ```
105
+ */
106
+ const cli = ReleaseCLi()
107
+ assert.ok(cli.logger)
108
+ })
109
+
110
+ /**
111
+ * @docs
112
+ * Show release details:
113
+ */
114
+ it('How to show release information?', () => {
115
+ /**
116
+ * ```bash
117
+ * release show [--full]
118
+ * ```
119
+ */
120
+ const release = new Release({
121
+ version: 'v1.0.0',
122
+ createdAt: new Date('2025-08-20'),
123
+ })
124
+ console.info(release.version) // v1.0.0
125
+ assert.strictEqual(console.output()[0][1], 'v1.0.0')
126
+ })
127
+
128
+ /**
129
+ * @docs
130
+ * List all releases in the project:
131
+ */
132
+ it('How to list all releases?', () => {
133
+ /**
134
+ * ```bash
135
+ * release list [--json]
136
+ * ```
137
+ */
138
+ const cli = ReleaseCLi()
139
+ assert.ok(cli.logger)
140
+ })
141
+
142
+ /**
143
+ * @docs
144
+ * Add a chat message to the current release:
145
+ */
146
+ it('How to write a release chat message?', () => {
147
+ /**
148
+ * ```bash
149
+ * release chat write --user alice "Issue with the build pipeline"
150
+ * ```
151
+ */
152
+ const cli = ReleaseCLi()
153
+ assert.ok(cli.logger)
154
+ })
155
+
156
+ /**
157
+ * @docs
158
+ * Host a static server for viewing releases:
159
+ */
160
+ it('How to host release UI?', () => {
161
+ /**
162
+ * ```bash
163
+ * release host [--webui] [--port 3000]
164
+ * ```
165
+ */
166
+ const cli = ReleaseCLi()
167
+ assert.ok(cli.logger)
168
+ })
169
+
170
+ /**
171
+ * @docs
172
+ * Serve all release files for local inspection:
173
+ */
174
+ it('How to serve release static assets?', () => {
175
+ /**
176
+ * ```bash
177
+ * release serve [--port 8080]
178
+ * ```
179
+ */
180
+ const cli = ReleaseCLi()
181
+ assert.ok(cli.logger)
182
+ })
183
+
184
+ /**
185
+ * @docs
186
+ * Validate release tasks and integrity:
187
+ */
188
+ it('How to validate release tasks?', () => {
189
+ /**
190
+ * ```bash
191
+ * release validate [--ignore-fail]
192
+ * ```
193
+ */
194
+ const release = new Release({
195
+ version: 'v1.0.0',
196
+ createdAt: new Date('2025-08-20'),
197
+ })
198
+ assert.ok(release instanceof Release)
199
+ })
200
+
201
+ /**
202
+ * @docs
203
+ * Seal the release with retro reflection:
204
+ */
205
+ it('How to seal a release?', () => {
206
+ /**
207
+ * ```bash
208
+ * release seal [--message "All core APIs are stable and tested"]
209
+ * ```
210
+ */
211
+ const cli = ReleaseCLi()
212
+ assert.ok(cli.logger)
213
+ })
214
+
215
+ /**
216
+ * @docs
217
+ * ## Core Concepts
218
+ *
219
+ * ### 1. Release as Object
220
+ *
221
+ * A `Release` is a structured class containing:
222
+ * - `version`: release identifier (vX.Y.Z).
223
+ * - `createdAt`, `startAt`, `planAt`, `completeAt`: datetime milestones.
224
+ * - `document`: parsed markdown document with structure-aware parsing.
225
+ *
226
+ * Each property is typed and validated automatically via JSDoc and runtime parsing.
227
+ */
228
+ it('How to instantiate a Release?', () => {
229
+ //import { Release } from '@nan0web/release'
230
+ const release = new Release({
231
+ version: 'v1.0.0',
232
+ createdAt: '2025-08-20T10:00:00Z',
233
+ })
234
+ console.info(release.version) // ← v1.0.0
235
+ console.info(release.createdAt instanceof Date) // ← true
236
+
237
+ assert.strictEqual(console.output()[0][1], 'v1.0.0')
238
+ assert.strictEqual(console.output()[1][1], true)
239
+ })
240
+
241
+ /**
242
+ * @docs
243
+ * ### 2. Release Document Parsing
244
+ *
245
+ * A `ReleaseDocument` extends `@nan0web/markdown` with:
246
+ * - Structured parsing of markdown release notes
247
+ * - Extraction of sections and tasks
248
+ * - Team and role parsing from markdown frontmatter or code
249
+ */
250
+ it('How to parse release notes markdown into structured data?', () => {
251
+ //import { ReleaseDocument } from '@nan0web/release'
252
+ const md = `# v1.0.0 - 2025-08-20
253
+
254
+ ## Overview
255
+ Release milestone includes UI polish and core API stabilization.
256
+
257
+ ### Tasks
258
+ ### Done **Implement core UI design** [ui.core-design]
259
+ ### InProgress **Fix responsive issues in mobile layout** [ui.mobile-fixes]`
260
+
261
+ const doc = ReleaseDocument.from(md)
262
+ console.info(doc.version) // ← v1.0.0
263
+ console.info(doc.date instanceof Date) // ← true
264
+ console.info(doc.document.children instanceof Array) // ← true
265
+
266
+ assert.strictEqual(console.output()[0][1], 'v1.0.0')
267
+ assert.strictEqual(console.output()[1][1], true)
268
+ assert.strictEqual(console.output()[2][1], true)
269
+ })
270
+
271
+ /**
272
+ * @docs
273
+ * ### 3. Person & Team Structures
274
+ *
275
+ * A `Person` instance includes:
276
+ * - `name`: HumanName
277
+ * - `gender`: HumanGender
278
+ * - `contacts`: array of HumanContact
279
+ */
280
+ it('How to create a Person with typed properties?', () => {
281
+ //import { Person } from '@nan0web/release'
282
+ const person = new Person({
283
+ name: ['Alice', 'Developer'],
284
+ gender: 'female',
285
+ contacts: ['mailto:alice@example.com'],
286
+ })
287
+ console.info(person.name.firstName) // ← Alice
288
+ console.info(person.contacts.length >= 0) // ← true
289
+
290
+ assert.strictEqual(console.output()[0][1], 'Alice')
291
+ assert.strictEqual(console.output()[1][1], true)
292
+ })
293
+
294
+ /**
295
+ * @docs
296
+ * ## Architecture: Project Management as Code
297
+ *
298
+ * This architecture treats tasks as tests, roles as classes, and progress as validated outcomes.
299
+ *
300
+ * ### Task Management
301
+ *
302
+ * Tasks are registered as `taskId` → `testFilePath` in `ProjectManagement`.
303
+ * Their status is derived by running `node:test` suites.
304
+ */
305
+ it('How to register and validate tasks as tests?', async () => {
306
+ //import { ProjectManagement } from '@nan0web/release'
307
+ const pm = new ProjectManagement()
308
+ pm.registerTask('task-1', './tests/task1.test.js')
309
+ pm.registerTask('task-2', './tests/task2.test.js')
310
+
311
+ const mockResults = {
312
+ passed: ['task-1'],
313
+ failed: [],
314
+ pending: ['task-2'],
315
+ }
316
+
317
+ pm.validateProjectState = async () => mockResults
318
+ const results = await pm.validateProjectState()
319
+
320
+ console.info(results.passed.includes('task-1')) // ← true
321
+ console.info(results.pending.includes('task-2')) // ← true
322
+
323
+ assert.strictEqual(console.output()[0][1], true)
324
+ assert.strictEqual(console.output()[1][1], true)
325
+ })
326
+
327
+ /**
328
+ * @docs
329
+ * ### Release Processing
330
+ *
331
+ * The `ReleaseManager` coordinates releases and validates readiness.
332
+ * It ensures:
333
+ * - All registered tests pass
334
+ * - Version is correctly incremented
335
+ * - Git tag is applied if all validations succeed
336
+ */
337
+ it('How to execute a release after validation?', async () => {
338
+ //import { ReleaseManager, ProjectManagement } from '@nan0web/release'
339
+ const pm = new ProjectManagement()
340
+ const rm = new ReleaseManager(pm)
341
+
342
+ rm.calculateVersion = () => 'v1.0.1'
343
+ rm.publish = async () => true
344
+
345
+ const result = await rm.executeRelease('patch')
346
+ console.info(result.version) // ← v1.0.1
347
+ console.info(result.published) // ← true
348
+
349
+ assert.strictEqual(console.output()[0][1], 'v1.0.1')
350
+ assert.strictEqual(console.output()[1][1], true)
351
+ })
352
+
353
+ /**
354
+ * @docs
355
+ * ### Changelog Integration
356
+ *
357
+ * Using `ChangelogTaskManager`, you can:
358
+ * - Extract task definitions from changelog entries
359
+ * - Generate corresponding test files
360
+ * - Automate task progression in CI
361
+ */
362
+ it('How to parse changelog and extract tasks?', () => {
363
+ //import { ChangelogTaskManager } from '@nan0web/release'
364
+ const ctm = new ChangelogTaskManager()
365
+ const changelog = `# Changelog
366
+
367
+ ## [1.0.0] - 2025-08-20
368
+ ### Added
369
+ - Initial structure [core.init]
370
+ - Release notes support [docs.release-notes]`
371
+
372
+ const tasks = ctm.parseChangelog(changelog)
373
+ console.info(Array.isArray(tasks)) // ← true
374
+ console.info(tasks.length >= 0) // ← true
375
+
376
+ assert.strictEqual(console.output()[0][1], true)
377
+ assert.strictEqual(console.output()[1][1], true)
378
+ })
379
+
380
+ /**
381
+ * @docs
382
+ * ## Java•Script Features
383
+ */
384
+ it('Uses JSDoc and .d.ts files for autocompletion', () => {
385
+ assert.ok(pkg.types)
386
+ assert.ok(pkg.types.includes('.d.ts'))
387
+ })
388
+
389
+ /**
390
+ * @docs
391
+ * ## CLI Playground
392
+ *
393
+ * Try the package in the terminal:
394
+ */
395
+ it('How to run playground demo?', async () => {
396
+ /**
397
+ * ```bash
398
+ * git clone https://github.com/nan0web/release.git
399
+ * cd release
400
+ * pnpm install
401
+ * pnpm run playground
402
+ * ```
403
+ */
404
+ assert.ok(pkg.scripts?.playground)
405
+ const response = await runSpawn('git', ['remote', 'get-url', 'origin'])
406
+ assert.ok(response.code === 0)
407
+ assert.ok(response.text.trim().endsWith(':nan0web/release.git'))
408
+ })
409
+
410
+ /**
411
+ * @docs
412
+ * ## Project Status
413
+ *
414
+ * To verify the project is ready, run:
415
+ */
416
+ it('How to check project status before publishing?', async () => {
417
+ /**
418
+ * ```bash
419
+ * npm test
420
+ * npm run test:coverage
421
+ * npm run test:status
422
+ * ```
423
+ */
424
+ assert.ok(pkg.scripts?.test)
425
+ assert.ok(pkg.scripts?.['test:coverage'])
426
+ assert.ok(pkg.scripts?.['test:status'])
427
+ })
428
+
429
+ /**
430
+ * @docs
431
+ * ## Contributing
432
+ */
433
+ it('How to contribute? - [check here](./CONTRIBUTING.md)', async () => {
434
+ assert.equal(pkg.scripts?.precommit, 'npm test')
435
+ assert.equal(pkg.scripts?.prepush, 'npm test')
436
+ assert.equal(pkg.scripts?.prepare, 'husky')
437
+ })
438
+
439
+ /**
440
+ * @docs
441
+ * ## License
442
+ */
443
+ it('How to license ISC? - [check here](./LICENSE)', async () => {
444
+ /** @docs */
445
+ const text = await fs.loadDocument('LICENSE')
446
+ assert.ok(String(text).includes('ISC'))
447
+ })
448
+ }
449
+
450
+ describe('README.md testing', testRender)
451
+
452
+ describe('Rendering README.md', async () => {
453
+ let text = ''
454
+ const format = new Intl.NumberFormat('en-US').format
455
+ const parser = new DocsParser()
456
+ text = String(parser.decode(testRender))
457
+ await fs.saveDocument('README.md', text)
458
+ const dataset = DatasetParser.parse(text, pkg.name)
459
+ await fs.saveDocument('.datasets/README.dataset.jsonl', dataset)
460
+
461
+ it(`document is rendered [${format(Buffer.byteLength(text))}b]`, async () => {
462
+ const text = await readFile('README.md', 'utf8')
463
+ assert.ok(text.includes('## License'))
464
+ })
465
+ })