@nan0web/release 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -42
- package/bin/nan0release.js +27 -42
- package/package.json +21 -14
- package/src/Release/Document.js +13 -19
- package/src/Release/MarkdownToTest.js +35 -33
- package/src/Release/Person.js +3 -8
- package/src/Release/Scanner.js +179 -0
- package/src/Release.js +19 -12
- package/src/Team.js +9 -9
- package/src/architecture/ProjectManagementAsCode.js +8 -8
- package/src/cli/index.js +9 -0
- package/src/co/AppCommandOptions.js +4 -6
- package/src/commands/CloseCommand.js +67 -0
- package/src/commands/Command.js +48 -0
- package/src/commands/DepsCommand.js +143 -0
- package/src/commands/InitCommand.js +48 -56
- package/src/commands/PublishCommand.js +80 -119
- package/src/commands/SpecCommand.js +41 -0
- package/src/commands/StatusCommand.js +26 -0
- package/src/db/ReleaseDB.js +5 -5
- package/src/index.js +18 -0
- package/src/ui/cli/ReleaseCLi.js +52 -0
- package/src/utils/runSpawn.js +0 -0
- package/types/Release/Document.d.ts +2 -2
- package/types/Release/Person.d.ts +3 -3
- package/types/Release/Scanner.d.ts +90 -0
- package/types/Release.d.ts +37 -33
- package/types/ReleaseCLI.d.ts +29 -28
- package/types/Team.d.ts +3 -3
- package/types/architecture/ProjectManagementAsCode.d.ts +1 -1
- package/types/cli/index.d.ts +2 -0
- package/types/co/AppCommandMessage.d.ts +10 -11
- package/types/co/AppCommandOptions.d.ts +1 -2
- package/types/commands/BaseCommand.d.ts +23 -0
- package/types/commands/ChatCommand.d.ts +9 -9
- package/types/commands/ChatMessage.d.ts +36 -0
- package/types/commands/CloseCommand.d.ts +25 -0
- package/types/commands/Command.d.ts +28 -0
- package/types/commands/DepsCommand.d.ts +32 -0
- package/types/commands/DepsMessage.d.ts +28 -0
- package/types/commands/HostCommand.d.ts +7 -7
- package/types/commands/HostMessage.d.ts +44 -0
- package/types/commands/InitCommand.d.ts +24 -19
- package/types/commands/InitMessage.d.ts +24 -0
- package/types/commands/ListCommand.d.ts +8 -8
- package/types/commands/ListMessage.d.ts +30 -0
- package/types/commands/PublishCommand.d.ts +36 -47
- package/types/commands/PublishMessage.d.ts +39 -0
- package/types/commands/SealCommand.d.ts +7 -7
- package/types/commands/SealMessage.d.ts +28 -0
- package/types/commands/ServeCommand.d.ts +7 -7
- package/types/commands/ServeMessage.d.ts +30 -0
- package/types/commands/ShowCommand.d.ts +7 -7
- package/types/commands/SpecCommand.d.ts +25 -0
- package/types/commands/StatusCommand.d.ts +9 -0
- package/types/commands/SubCommand.d.ts +9 -7
- package/types/commands/ValidateCommand.d.ts +7 -7
- package/types/commands/ValidateMessage.d.ts +20 -0
- package/types/db/ReleaseDB.d.ts +2 -2
- package/types/index.d.ts +10 -0
- package/types/ui/cli/ReleaseCLi.d.ts +10 -0
- package/types/ui/cli/index.d.ts +0 -0
- package/types/utils/runSpawn.d.ts +0 -0
- package/.datasets/README.dataset.jsonl +0 -19
- package/.editorconfig +0 -20
- package/CHANGELOG.md +0 -6
- package/CONTRIBUTING.md +0 -42
- package/bin/commands/InitCommand.js +0 -10
- package/bin/lib/functions.js +0 -240
- package/bin/lib/functions.test.js +0 -138
- package/bin/release.js +0 -12
- package/bin/release.test.js +0 -73
- package/bin/temp/package.json +0 -1
- package/docs/system.uk.md +0 -413
- package/docs/uk/README.md +0 -284
- package/legacy/PrepareCommand.js +0 -154
- package/legacy/PrepareCommand.test.js +0 -189
- package/legacy/changelog.js +0 -446
- package/releases/1/0/v1.0.0/models/Person.js +0 -26
- package/releases/1/0/v1.0.0/models/Person.test.js +0 -44
- package/releases/1/0/v1.0.0/models/company.js +0 -11
- package/releases/1/0/v1.0.0/models/members.js +0 -14
- package/releases/1/0/v1.0.0/models/members.test.js +0 -21
- package/releases/1/0/v1.0.0/models/teams/DevTeam.js +0 -6
- package/releases/1/0/v1.0.0/models/teams/DevTeam.test.js +0 -15
- package/releases/1/0/v1.0.0/models/teams/index.js +0 -5
- package/releases/1/0/v1.0.0/release.js +0 -12
- package/releases/1/0/v1.0.0/release.md +0 -121
- package/releases/1/0/v1.0.0/release.test.js +0 -36
- package/releases/1/0/v1.0.0/test/YaRaSLove/git-native.test.js +0 -14
- package/releases/current.js +0 -3
- package/releases/index.js +0 -11
- package/src/README.md.js +0 -468
- package/src/Release/MarkdownToTest.test.js +0 -60
- package/src/ReleaseCLI.js +0 -122
- package/src/architecture/ProjectManagementAsCode.test.js +0 -128
- package/src/co/AppCommandMessage.js +0 -22
- package/src/commands/ChatCommand.js +0 -56
- package/src/commands/HostCommand.js +0 -63
- package/src/commands/ListCommand.js +0 -56
- package/src/commands/SealCommand.js +0 -51
- package/src/commands/ServeCommand.js +0 -53
- package/src/commands/ShowCommand.js +0 -58
- package/src/commands/SubCommand.js +0 -21
- package/src/commands/ValidateCommand.js +0 -66
- package/system.md +0 -571
- package/tsconfig.json +0 -23
- /package/{bin/lib/temp/pnpm-lock.yaml → src/ui/cli/index.js} +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @nan0web/release
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|---|---|---|---|---|---|
|
|
5
|
-
|[@nan0web/release](https://github.com/nan0web/release/) |🟢 `97.1%` |🧪 [English 🏴](https://github.com/nan0web/release/blob/main/README.md)<br />[Українською 🇺🇦](https://github.com/nan0web/release/blob/main/docs/uk/README.md) |🟡 `84.2%` |✅ d.ts 📜 system.md 🕹️ playground |— |
|
|
3
|
+
<!-- %PACKAGE_STATUS% -->
|
|
6
4
|
|
|
7
5
|
Project management as code, Git-native, GPG-signed, and test-driven.
|
|
8
6
|
|
|
@@ -44,7 +42,7 @@ How to initialize a new release version?
|
|
|
44
42
|
release init v1.0.0
|
|
45
43
|
```
|
|
46
44
|
|
|
47
|
-
const cli =
|
|
45
|
+
const cli = ReleaseCLi()
|
|
48
46
|
Show release details:
|
|
49
47
|
|
|
50
48
|
How to show release information?
|
|
@@ -53,8 +51,8 @@ release show [--full]
|
|
|
53
51
|
```
|
|
54
52
|
|
|
55
53
|
const release = new Release({
|
|
56
|
-
version:
|
|
57
|
-
createdAt: new Date(
|
|
54
|
+
version: 'v1.0.0',
|
|
55
|
+
createdAt: new Date('2025-08-20'),
|
|
58
56
|
})
|
|
59
57
|
console.info(release.version) // v1.0.0
|
|
60
58
|
List all releases in the project:
|
|
@@ -64,7 +62,7 @@ How to list all releases?
|
|
|
64
62
|
release list [--json]
|
|
65
63
|
```
|
|
66
64
|
|
|
67
|
-
const cli =
|
|
65
|
+
const cli = ReleaseCLi()
|
|
68
66
|
Add a chat message to the current release:
|
|
69
67
|
|
|
70
68
|
How to write a release chat message?
|
|
@@ -72,7 +70,7 @@ How to write a release chat message?
|
|
|
72
70
|
release chat write --user alice "Issue with the build pipeline"
|
|
73
71
|
```
|
|
74
72
|
|
|
75
|
-
const cli =
|
|
73
|
+
const cli = ReleaseCLi()
|
|
76
74
|
Host a static server for viewing releases:
|
|
77
75
|
|
|
78
76
|
How to host release UI?
|
|
@@ -80,7 +78,7 @@ How to host release UI?
|
|
|
80
78
|
release host [--webui] [--port 3000]
|
|
81
79
|
```
|
|
82
80
|
|
|
83
|
-
const cli =
|
|
81
|
+
const cli = ReleaseCLi()
|
|
84
82
|
Serve all release files for local inspection:
|
|
85
83
|
|
|
86
84
|
How to serve release static assets?
|
|
@@ -88,7 +86,7 @@ How to serve release static assets?
|
|
|
88
86
|
release serve [--port 8080]
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
const cli =
|
|
89
|
+
const cli = ReleaseCLi()
|
|
92
90
|
Validate release tasks and integrity:
|
|
93
91
|
|
|
94
92
|
How to validate release tasks?
|
|
@@ -97,8 +95,8 @@ release validate [--ignore-fail]
|
|
|
97
95
|
```
|
|
98
96
|
|
|
99
97
|
const release = new Release({
|
|
100
|
-
version:
|
|
101
|
-
createdAt: new Date(
|
|
98
|
+
version: 'v1.0.0',
|
|
99
|
+
createdAt: new Date('2025-08-20'),
|
|
102
100
|
})
|
|
103
101
|
Seal the release with retro reflection:
|
|
104
102
|
|
|
@@ -107,7 +105,7 @@ How to seal a release?
|
|
|
107
105
|
release seal [--message "All core APIs are stable and tested"]
|
|
108
106
|
```
|
|
109
107
|
|
|
110
|
-
const cli =
|
|
108
|
+
const cli = ReleaseCLi()
|
|
111
109
|
## Core Concepts
|
|
112
110
|
|
|
113
111
|
### 1. Release as Object
|
|
@@ -123,12 +121,11 @@ How to instantiate a Release?
|
|
|
123
121
|
```js
|
|
124
122
|
import { Release } from '@nan0web/release'
|
|
125
123
|
const release = new Release({
|
|
126
|
-
version:
|
|
127
|
-
createdAt:
|
|
124
|
+
version: 'v1.0.0',
|
|
125
|
+
createdAt: '2025-08-20T10:00:00Z',
|
|
128
126
|
})
|
|
129
127
|
console.info(release.version) // ← v1.0.0
|
|
130
128
|
console.info(release.createdAt instanceof Date) // ← true
|
|
131
|
-
|
|
132
129
|
```
|
|
133
130
|
### 2. Release Document Parsing
|
|
134
131
|
|
|
@@ -141,19 +138,15 @@ How to parse release notes markdown into structured data?
|
|
|
141
138
|
```js
|
|
142
139
|
import { ReleaseDocument } from '@nan0web/release'
|
|
143
140
|
const md = `# v1.0.0 - 2025-08-20
|
|
144
|
-
|
|
145
141
|
## Overview
|
|
146
142
|
Release milestone includes UI polish and core API stabilization.
|
|
147
|
-
|
|
148
143
|
### Tasks
|
|
149
144
|
### Done **Implement core UI design** [ui.core-design]
|
|
150
145
|
### InProgress **Fix responsive issues in mobile layout** [ui.mobile-fixes]`
|
|
151
|
-
|
|
152
146
|
const doc = ReleaseDocument.from(md)
|
|
153
147
|
console.info(doc.version) // ← v1.0.0
|
|
154
148
|
console.info(doc.date instanceof Date) // ← true
|
|
155
149
|
console.info(doc.document.children instanceof Array) // ← true
|
|
156
|
-
|
|
157
150
|
```
|
|
158
151
|
### 3. Person & Team Structures
|
|
159
152
|
|
|
@@ -166,13 +159,12 @@ How to create a Person with typed properties?
|
|
|
166
159
|
```js
|
|
167
160
|
import { Person } from '@nan0web/release'
|
|
168
161
|
const person = new Person({
|
|
169
|
-
name: [
|
|
170
|
-
gender:
|
|
171
|
-
contacts: [
|
|
162
|
+
name: ['Alice', 'Developer'],
|
|
163
|
+
gender: 'female',
|
|
164
|
+
contacts: ['mailto:alice@example.com'],
|
|
172
165
|
})
|
|
173
166
|
console.info(person.name.firstName) // ← Alice
|
|
174
167
|
console.info(person.contacts.length >= 0) // ← true
|
|
175
|
-
|
|
176
168
|
```
|
|
177
169
|
## Architecture: Project Management as Code
|
|
178
170
|
|
|
@@ -187,21 +179,17 @@ How to register and validate tasks as tests?
|
|
|
187
179
|
```js
|
|
188
180
|
import { ProjectManagement } from '@nan0web/release'
|
|
189
181
|
const pm = new ProjectManagement()
|
|
190
|
-
pm.registerTask(
|
|
191
|
-
pm.registerTask(
|
|
192
|
-
|
|
182
|
+
pm.registerTask('task-1', './tests/task1.test.js')
|
|
183
|
+
pm.registerTask('task-2', './tests/task2.test.js')
|
|
193
184
|
const mockResults = {
|
|
194
|
-
passed: [
|
|
185
|
+
passed: ['task-1'],
|
|
195
186
|
failed: [],
|
|
196
|
-
pending: [
|
|
187
|
+
pending: ['task-2'],
|
|
197
188
|
}
|
|
198
|
-
|
|
199
189
|
pm.validateProjectState = async () => mockResults
|
|
200
190
|
const results = await pm.validateProjectState()
|
|
201
|
-
|
|
202
|
-
console.info(results.
|
|
203
|
-
console.info(results.pending.includes("task-2")) // ← true
|
|
204
|
-
|
|
191
|
+
console.info(results.passed.includes('task-1')) // ← true
|
|
192
|
+
console.info(results.pending.includes('task-2')) // ← true
|
|
205
193
|
```
|
|
206
194
|
### Release Processing
|
|
207
195
|
|
|
@@ -216,14 +204,11 @@ How to execute a release after validation?
|
|
|
216
204
|
import { ReleaseManager, ProjectManagement } from '@nan0web/release'
|
|
217
205
|
const pm = new ProjectManagement()
|
|
218
206
|
const rm = new ReleaseManager(pm)
|
|
219
|
-
|
|
220
|
-
rm.calculateVersion = () => "v1.0.1"
|
|
207
|
+
rm.calculateVersion = () => 'v1.0.1'
|
|
221
208
|
rm.publish = async () => true
|
|
222
|
-
|
|
223
|
-
const result = await rm.executeRelease("patch")
|
|
209
|
+
const result = await rm.executeRelease('patch')
|
|
224
210
|
console.info(result.version) // ← v1.0.1
|
|
225
211
|
console.info(result.published) // ← true
|
|
226
|
-
|
|
227
212
|
```
|
|
228
213
|
### Changelog Integration
|
|
229
214
|
|
|
@@ -237,16 +222,13 @@ How to parse changelog and extract tasks?
|
|
|
237
222
|
import { ChangelogTaskManager } from '@nan0web/release'
|
|
238
223
|
const ctm = new ChangelogTaskManager()
|
|
239
224
|
const changelog = `# Changelog
|
|
240
|
-
|
|
241
225
|
## [1.0.0] - 2025-08-20
|
|
242
226
|
### Added
|
|
243
227
|
- Initial structure [core.init]
|
|
244
228
|
- Release notes support [docs.release-notes]`
|
|
245
|
-
|
|
246
229
|
const tasks = ctm.parseChangelog(changelog)
|
|
247
230
|
console.info(Array.isArray(tasks)) // ← true
|
|
248
231
|
console.info(tasks.length >= 0) // ← true
|
|
249
|
-
|
|
250
232
|
```
|
|
251
233
|
## Java•Script Features
|
|
252
234
|
|
package/bin/nan0release.js
CHANGED
|
@@ -1,57 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import process from
|
|
4
|
-
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
|
|
5
|
+
import { OutputMessage } from '@nan0web/co'
|
|
5
6
|
import Logger from '@nan0web/log'
|
|
6
|
-
import PublishCommand from "../src/commands/PublishCommand.js"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return super.success(this.PREFIX, ...args)
|
|
24
|
-
}
|
|
25
|
-
debug(...args) {
|
|
26
|
-
return super.debug(this.PREFIX, ...args)
|
|
8
|
+
import createReleaseCLI from '../src/ui/cli/ReleaseCLi.js'
|
|
9
|
+
|
|
10
|
+
class OutputLogger extends Logger {
|
|
11
|
+
log(first, ...args) {
|
|
12
|
+
if (first && first instanceof OutputMessage) {
|
|
13
|
+
if (OutputMessage.TYPES.ERROR === first.type) {
|
|
14
|
+
return this.error(first.content, ...args)
|
|
15
|
+
} else if (OutputMessage.TYPES.WARNING === first.type) {
|
|
16
|
+
return this.warn(first.content, ...args)
|
|
17
|
+
} else if (OutputMessage.TYPES.SUCCESS === first.type) {
|
|
18
|
+
return this.success(first.content, ...args)
|
|
19
|
+
}
|
|
20
|
+
return this.info(first.content, ...args)
|
|
21
|
+
}
|
|
22
|
+
return super.log(first, ...args)
|
|
27
23
|
}
|
|
28
24
|
}
|
|
29
25
|
|
|
30
|
-
const logger = new
|
|
31
|
-
|
|
32
|
-
const mainCommand = new Command({
|
|
33
|
-
name: "nan0release",
|
|
34
|
-
help: "Release utilities for nan0web packages",
|
|
35
|
-
logger,
|
|
36
|
-
subcommands: [
|
|
37
|
-
new PublishCommand({ logger }),
|
|
38
|
-
]
|
|
39
|
-
})
|
|
26
|
+
const logger = new OutputLogger(Logger.detectLevel(process.argv))
|
|
40
27
|
|
|
41
28
|
async function main(argv = []) {
|
|
42
|
-
const
|
|
43
|
-
logger.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} else {
|
|
49
|
-
logger.info(mainCommand.runHelp())
|
|
29
|
+
const cli = createReleaseCLI(argv, logger)
|
|
30
|
+
logger.info(Logger.style(Logger.LOGO, { color: Logger.MAGENTA }))
|
|
31
|
+
|
|
32
|
+
const stream = cli.run()
|
|
33
|
+
for await (const entry of stream) {
|
|
34
|
+
logger.info(entry)
|
|
50
35
|
}
|
|
51
36
|
}
|
|
52
37
|
|
|
53
|
-
main(process.argv).catch(err => {
|
|
54
|
-
logger.error(
|
|
38
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
39
|
+
logger.error('❌ Unhandled error:', err.message || err)
|
|
55
40
|
if (err.stack) logger.debug(err.stack)
|
|
56
41
|
process.exit(1)
|
|
57
42
|
})
|
package/package.json
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nan0web/release",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Project Management as Code, Git-Native, GPG-Signed, Test-Driven",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"bin": {
|
|
9
9
|
"nan0release": "./bin/nan0release.js",
|
|
10
|
-
"release": "./bin/
|
|
10
|
+
"release": "./bin/nan0release.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
14
|
"clean": "rm -rf .cache/ && rm -rf dist/",
|
|
15
15
|
"clean:modules": "rm -rf node_modules",
|
|
16
|
-
"test": "node --test \"src/**/*.test.js\"
|
|
16
|
+
"test": "node --test \"src/**/*.test.js\"",
|
|
17
|
+
"test1": "node --test \"src/**/*.test.js\" | nan0test parse --fail",
|
|
17
18
|
"test:docs": "node --test \"src/README.md.js\"",
|
|
18
19
|
"test:release": "node --test \"releases/**/*.test.js\"",
|
|
19
20
|
"test:coverage": "node --experimental-test-coverage --test-coverage-include=\"src/**/*.js\" --test-coverage-exclude=\"src/**/*.test.js\" --test \"src/**/*.test.js\"",
|
|
20
21
|
"test:coverage:collect": "nan0test coverage",
|
|
21
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",
|
|
22
26
|
"release": "node ./bin/nan0release.js publish",
|
|
23
27
|
"precommit": "npm test",
|
|
24
28
|
"prepush": "npm test",
|
|
@@ -26,18 +30,21 @@
|
|
|
26
30
|
"playground": "node playground/main.js"
|
|
27
31
|
},
|
|
28
32
|
"dependencies": {
|
|
29
|
-
"@nan0web/changelog": "
|
|
30
|
-
"@nan0web/co": "
|
|
31
|
-
"@nan0web/db": "
|
|
32
|
-
"@nan0web/db-fs": "
|
|
33
|
-
"@nan0web/log": "
|
|
34
|
-
"@nan0web/markdown": "
|
|
35
|
-
"@nan0web/types": "
|
|
36
|
-
"@nan0web/
|
|
37
|
-
"
|
|
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"
|
|
38
44
|
},
|
|
39
45
|
"devDependencies": {
|
|
40
|
-
"@nan0web/test": "
|
|
41
|
-
"husky": "^9.1.7"
|
|
46
|
+
"@nan0web/test": "*",
|
|
47
|
+
"husky": "^9.1.7",
|
|
48
|
+
"knip": "^5.85.0"
|
|
42
49
|
}
|
|
43
50
|
}
|
package/src/Release/Document.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Markdown, { MDElement, MDHeading1, MDHeading2, MDHeading3 } from
|
|
2
|
-
import Person from
|
|
1
|
+
import Markdown, { MDElement, MDHeading1, MDHeading2, MDHeading3 } from '@nan0web/markdown'
|
|
2
|
+
import Person from './Person.js'
|
|
3
3
|
|
|
4
4
|
class ReleaseDocument extends Markdown {
|
|
5
5
|
/** @type {Person[]} */
|
|
@@ -20,15 +20,10 @@ class ReleaseDocument extends Markdown {
|
|
|
20
20
|
*/
|
|
21
21
|
constructor(options = {}) {
|
|
22
22
|
super()
|
|
23
|
-
const {
|
|
24
|
-
team = [],
|
|
25
|
-
roles = new Map(),
|
|
26
|
-
version = "",
|
|
27
|
-
date
|
|
28
|
-
} = options
|
|
23
|
+
const { team = [], roles = new Map(), version = '', date } = options
|
|
29
24
|
this.version = String(version)
|
|
30
25
|
this.date = date ? new Date(date) : undefined
|
|
31
|
-
this.team = team.map(t => Person.from(t))
|
|
26
|
+
this.team = team.map((t) => Person.from(t))
|
|
32
27
|
this.roles = new Map(roles)
|
|
33
28
|
}
|
|
34
29
|
|
|
@@ -43,13 +38,13 @@ class ReleaseDocument extends Markdown {
|
|
|
43
38
|
|
|
44
39
|
const h1s = this.document.filter((el) => el instanceof MDHeading1)
|
|
45
40
|
if (h1s.length !== 1) {
|
|
46
|
-
throw new TypeError(
|
|
41
|
+
throw new TypeError('Release document must have exactly one H1 heading with version and date')
|
|
47
42
|
}
|
|
48
43
|
|
|
49
|
-
const h1Content = h1s[0].content ??
|
|
50
|
-
const [versionPart, ...dateParts] = h1Content.split(
|
|
44
|
+
const h1Content = h1s[0].content ?? ''
|
|
45
|
+
const [versionPart, ...dateParts] = h1Content.split(' - ')
|
|
51
46
|
this.version = versionPart.trim()
|
|
52
|
-
this.date = new Date(dateParts.join(
|
|
47
|
+
this.date = new Date(dateParts.join(' - ').trim())
|
|
53
48
|
|
|
54
49
|
const sections = []
|
|
55
50
|
/** @type {{title: string, tasks: Array} | null} */
|
|
@@ -58,11 +53,10 @@ class ReleaseDocument extends Markdown {
|
|
|
58
53
|
if (el instanceof MDHeading2) {
|
|
59
54
|
currentSection = {
|
|
60
55
|
title: el.content.trim(),
|
|
61
|
-
tasks: []
|
|
56
|
+
tasks: [],
|
|
62
57
|
}
|
|
63
58
|
sections.push(currentSection)
|
|
64
|
-
}
|
|
65
|
-
else if (el instanceof MDHeading3 && currentSection) {
|
|
59
|
+
} else if (el instanceof MDHeading3 && currentSection) {
|
|
66
60
|
const content = el.content.trim()
|
|
67
61
|
const statusMatch = content.match(/^(\w+)\s*(.+)$/)
|
|
68
62
|
const slugMatch = content.match(/\[([^\]]+)\]$/)
|
|
@@ -84,7 +78,7 @@ class ReleaseDocument extends Markdown {
|
|
|
84
78
|
currentSection.tasks.push({
|
|
85
79
|
content: taskContent,
|
|
86
80
|
status: status,
|
|
87
|
-
slug: slug
|
|
81
|
+
slug: slug,
|
|
88
82
|
})
|
|
89
83
|
}
|
|
90
84
|
}
|
|
@@ -98,7 +92,7 @@ class ReleaseDocument extends Markdown {
|
|
|
98
92
|
*/
|
|
99
93
|
static from(input) {
|
|
100
94
|
if (input instanceof ReleaseDocument) return input
|
|
101
|
-
if (typeof input ===
|
|
95
|
+
if (typeof input === 'string') {
|
|
102
96
|
const doc = new ReleaseDocument()
|
|
103
97
|
doc.parse(input)
|
|
104
98
|
return doc
|
|
@@ -107,4 +101,4 @@ class ReleaseDocument extends Markdown {
|
|
|
107
101
|
}
|
|
108
102
|
}
|
|
109
103
|
|
|
110
|
-
export default ReleaseDocument
|
|
104
|
+
export default ReleaseDocument
|
|
@@ -11,22 +11,22 @@ class MarkdownToTest {
|
|
|
11
11
|
generateTests(markdown) {
|
|
12
12
|
const lines = markdown.split('\n')
|
|
13
13
|
const versionMatch = markdown.match(/^#\s+(v[\d.]+)\s*-\s*(\d{4}-\d{2}-\d{2})/)
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
if (!versionMatch) {
|
|
16
16
|
throw new Error('Markdown must start with version header: # vX.Y.Z - YYYY-MM-DD')
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
const [, version, date] = versionMatch
|
|
20
20
|
let testCode = this.generateImports()
|
|
21
21
|
testCode += this.generateDescribeHeader(version, date)
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
const sections = this.extractSections(lines)
|
|
24
24
|
testCode += this.generateSectionTests(sections)
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
testCode += '})\n'
|
|
27
27
|
return testCode
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
/**
|
|
31
31
|
* Generate import statements for node:test
|
|
32
32
|
* @returns {string} Import code
|
|
@@ -37,7 +37,7 @@ import { ok, strictEqual } from "node:assert"
|
|
|
37
37
|
|
|
38
38
|
`
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
/**
|
|
42
42
|
* Generate main describe block header
|
|
43
43
|
* @param {string} version - Release version
|
|
@@ -48,7 +48,7 @@ import { ok, strictEqual } from "node:assert"
|
|
|
48
48
|
return `describe("${version} - ${date}", () => {
|
|
49
49
|
`
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
/**
|
|
53
53
|
* Extract sections from markdown lines
|
|
54
54
|
* @param {string[]} lines - Markdown lines
|
|
@@ -59,20 +59,20 @@ import { ok, strictEqual } from "node:assert"
|
|
|
59
59
|
const sections = []
|
|
60
60
|
/** @type {{title: string, tasks: Array<{content: string, status: string, slug: string}>} | null} */
|
|
61
61
|
let currentSection = null
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
for (let i = 0; i < lines.length; i++) {
|
|
64
64
|
const line = lines[i]
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
// H2 section
|
|
67
67
|
if (line.startsWith('## ')) {
|
|
68
68
|
currentSection = {
|
|
69
69
|
title: line.slice(3).trim(),
|
|
70
|
-
tasks: /** @type {Array<{content: string, status: string, slug: string}>} */([])
|
|
70
|
+
tasks: /** @type {Array<{content: string, status: string, slug: string}>} */ ([]),
|
|
71
71
|
}
|
|
72
72
|
sections.push(currentSection)
|
|
73
73
|
continue
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
// H3 task
|
|
77
77
|
if (line.startsWith('###') && currentSection) {
|
|
78
78
|
const statusMatch = line.match(/^###( Draft| InProgress)? \*\*(.+)\*\* \[(.+)\]$/)
|
|
@@ -81,16 +81,16 @@ import { ok, strictEqual } from "node:assert"
|
|
|
81
81
|
currentSection.tasks.push({
|
|
82
82
|
content,
|
|
83
83
|
status: status ? status.trim() : 'Done',
|
|
84
|
-
slug
|
|
84
|
+
slug,
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
continue
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
return sections
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
/**
|
|
95
95
|
* Generate test code for sections and their tasks
|
|
96
96
|
* @param {Array<{title: string, tasks: Array}>} sections - Sections with tasks
|
|
@@ -98,40 +98,42 @@ import { ok, strictEqual } from "node:assert"
|
|
|
98
98
|
*/
|
|
99
99
|
generateSectionTests(sections) {
|
|
100
100
|
let code = ''
|
|
101
|
-
|
|
102
|
-
sections.forEach(section => {
|
|
101
|
+
|
|
102
|
+
sections.forEach((section) => {
|
|
103
103
|
code += ` describe("${section.title}", () => {
|
|
104
104
|
`
|
|
105
|
-
|
|
106
|
-
section.tasks.forEach(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
|
|
106
|
+
section.tasks.forEach(
|
|
107
|
+
/** @param {{status: string, content: string}} task */ (task) => {
|
|
108
|
+
switch (task.status) {
|
|
109
|
+
case 'Draft':
|
|
110
|
+
code += ` it.todo("${task.content}", () => {
|
|
110
111
|
ok(false, "Draft task - not yet implemented")
|
|
111
112
|
})
|
|
112
113
|
`
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
break
|
|
115
|
+
case 'InProgress':
|
|
116
|
+
code += ` it.skip("${task.content}", () => {
|
|
116
117
|
ok(false, "In progress task - not yet completed")
|
|
117
118
|
})
|
|
118
119
|
`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
break
|
|
121
|
+
default: // Done
|
|
122
|
+
code += ` it("${task.content}", () => {
|
|
122
123
|
ok(true, "Task completed successfully")
|
|
123
124
|
})
|
|
124
125
|
`
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
|
|
129
131
|
code += ` })
|
|
130
132
|
`
|
|
131
133
|
})
|
|
132
|
-
|
|
134
|
+
|
|
133
135
|
return code
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
export default MarkdownToTest
|
|
139
|
+
export default MarkdownToTest
|
package/src/Release/Person.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HumanName, HumanContact, HumanGender } from
|
|
1
|
+
import { HumanName, HumanContact, HumanGender } from '@nan0web/verse'
|
|
2
2
|
|
|
3
3
|
export default class Person {
|
|
4
4
|
/** @type {HumanName} */
|
|
@@ -8,14 +8,10 @@ export default class Person {
|
|
|
8
8
|
/** @type {HumanContact[]} */
|
|
9
9
|
contacts
|
|
10
10
|
constructor(input = {}) {
|
|
11
|
-
const {
|
|
12
|
-
name = new HumanName([]),
|
|
13
|
-
gender = new HumanGender(-1),
|
|
14
|
-
contacts = []
|
|
15
|
-
} = input
|
|
11
|
+
const { name = new HumanName([]), gender = new HumanGender(-1), contacts = [] } = input
|
|
16
12
|
this.name = HumanName.from(name)
|
|
17
13
|
this.gender = HumanGender.from(gender)
|
|
18
|
-
this.contacts = contacts.map(c => HumanContact.from(c))
|
|
14
|
+
this.contacts = contacts.map((c) => HumanContact.from(c))
|
|
19
15
|
}
|
|
20
16
|
/**
|
|
21
17
|
* @param {*} input
|
|
@@ -26,4 +22,3 @@ export default class Person {
|
|
|
26
22
|
return new Person(input)
|
|
27
23
|
}
|
|
28
24
|
}
|
|
29
|
-
|