@nan0web/ui 1.1.0 → 1.3.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 +19 -14
- package/package.json +6 -4
- package/src/App/Command/DepsCommand.js +5 -9
- package/src/App/Core/CoreApp.js +18 -17
- package/src/App/Core/UI.js +11 -15
- package/src/App/Core/Widget.js +6 -10
- package/src/App/Core/index.js +3 -3
- package/src/App/Scenario.js +4 -4
- package/src/App/User/Command/Message.js +1 -1
- package/src/App/User/Command/index.js +1 -1
- package/src/App/User/UserApp.js +28 -21
- package/src/App/User/UserUI.js +2 -2
- package/src/App/User/index.js +2 -2
- package/src/App/index.js +5 -10
- package/src/Component/Process/Input.js +10 -17
- package/src/Component/Process/Process.js +3 -5
- package/src/Component/Process/index.js +2 -2
- package/src/Component/SortableList/SortableList.js +100 -0
- package/src/Component/SortableList/index.js +3 -0
- package/src/Component/Welcome/Input.js +2 -4
- package/src/Component/Welcome/Welcome.js +5 -9
- package/src/Component/Welcome/index.js +2 -2
- package/src/Component/index.js +5 -3
- package/src/Frame/Frame.js +163 -146
- package/src/Frame/Props.js +20 -20
- package/src/Locale.js +17 -18
- package/src/Model/User/User.js +3 -6
- package/src/Model/index.js +1 -1
- package/src/README.md.js +84 -94
- package/src/StdIn.js +8 -12
- package/src/StdOut.js +23 -27
- package/src/View/RenderOptions.js +1 -1
- package/src/View/View.js +40 -36
- package/src/core/Error/CancelError.js +2 -2
- package/src/core/Error/index.js +3 -5
- package/src/core/Flow.js +347 -0
- package/src/core/Form/Form.js +35 -33
- package/src/core/Form/Input.js +21 -6
- package/src/core/Form/Message.js +3 -6
- package/src/core/Form/index.js +4 -8
- package/src/core/InputAdapter.js +4 -6
- package/src/core/Message/Message.js +9 -12
- package/src/core/Message/OutputMessage.js +19 -17
- package/src/core/Message/index.js +2 -2
- package/src/core/OutputAdapter.js +12 -10
- package/src/core/Stream.js +1 -1
- package/src/core/StreamEntry.js +2 -2
- package/src/core/UiAdapter.js +31 -30
- package/src/core/index.js +33 -10
- package/src/functions.js +8 -15
- package/src/index.js +21 -32
- package/types/App/Command/DepsCommand.d.ts +1 -1
- package/types/App/Command/Options.d.ts +37 -40
- package/types/App/Command/index.d.ts +6 -6
- package/types/App/Core/CoreApp.d.ts +2 -2
- package/types/App/Core/UI.d.ts +4 -4
- package/types/App/Core/Widget.d.ts +4 -4
- package/types/App/Core/index.d.ts +3 -3
- package/types/App/Scenario.d.ts +1 -1
- package/types/App/User/Command/Message.d.ts +1 -1
- package/types/App/User/Command/Options.d.ts +29 -29
- package/types/App/User/Command/index.d.ts +1 -1
- package/types/App/User/UserApp.d.ts +5 -5
- package/types/App/User/index.d.ts +2 -2
- package/types/App/index.d.ts +4 -4
- package/types/Component/Process/Process.d.ts +2 -2
- package/types/Component/Process/index.d.ts +2 -2
- package/types/Component/SortableList/SortableList.d.ts +58 -0
- package/types/Component/SortableList/index.d.ts +2 -0
- package/types/Component/Welcome/Input.d.ts +1 -1
- package/types/Component/Welcome/Welcome.d.ts +1 -1
- package/types/Component/Welcome/index.d.ts +2 -2
- package/types/Component/index.d.ts +5 -3
- package/types/Frame/Frame.d.ts +1 -1
- package/types/Frame/Props.d.ts +1 -1
- package/types/Model/index.d.ts +1 -1
- package/types/StdIn.d.ts +2 -2
- package/types/StdOut.d.ts +1 -1
- package/types/View/View.d.ts +7 -7
- package/types/core/Error/index.d.ts +1 -1
- package/types/core/Flow.d.ts +320 -0
- package/types/core/Form/Form.d.ts +2 -2
- package/types/core/Form/Input.d.ts +11 -0
- package/types/core/Form/Message.d.ts +1 -1
- package/types/core/Form/index.d.ts +3 -3
- package/types/core/InputAdapter.d.ts +2 -2
- package/types/core/Intent.d.ts +65 -68
- package/types/core/Message/InputMessage.d.ts +65 -65
- package/types/core/Message/Message.d.ts +1 -1
- package/types/core/Message/OutputMessage.d.ts +1 -1
- package/types/core/Message/index.d.ts +2 -2
- package/types/core/Stream.d.ts +1 -1
- package/types/core/UiAdapter.d.ts +5 -5
- package/types/core/index.d.ts +4 -3
- package/types/index.d.ts +10 -10
package/README.md
CHANGED
|
@@ -73,19 +73,24 @@ How to define and validate a UiForm?
|
|
|
73
73
|
```js
|
|
74
74
|
import { UiForm } from '@nan0web/ui'
|
|
75
75
|
const form = new UiForm({
|
|
76
|
-
title:
|
|
76
|
+
title: 'Contact Form',
|
|
77
77
|
fields: [
|
|
78
|
-
FormInput.from({ name:
|
|
79
|
-
FormInput.from({
|
|
78
|
+
FormInput.from({ name: 'email', label: 'Email Address', type: 'email', required: true }),
|
|
79
|
+
FormInput.from({
|
|
80
|
+
name: 'message',
|
|
81
|
+
label: 'Your Message',
|
|
82
|
+
type: 'textarea',
|
|
83
|
+
required: true,
|
|
84
|
+
}),
|
|
80
85
|
],
|
|
81
86
|
state: {
|
|
82
|
-
email:
|
|
83
|
-
message:
|
|
84
|
-
}
|
|
87
|
+
email: 'invalid-email',
|
|
88
|
+
message: 'Hello!',
|
|
89
|
+
},
|
|
85
90
|
})
|
|
86
91
|
const errors = form.validate()
|
|
87
92
|
console.info(errors.size) // ← 1
|
|
88
|
-
console.info(errors.get(
|
|
93
|
+
console.info(errors.get('email')) // ← Invalid email format
|
|
89
94
|
```
|
|
90
95
|
### Components
|
|
91
96
|
|
|
@@ -97,8 +102,8 @@ Components render data as frame-ready output.
|
|
|
97
102
|
How to render the Welcome component?
|
|
98
103
|
```js
|
|
99
104
|
import { Welcome } from '@nan0web/ui'
|
|
100
|
-
const frame = Welcome({ user: { name:
|
|
101
|
-
const firstLine = frame[0].join(
|
|
105
|
+
const frame = Welcome({ user: { name: 'Alice' } })
|
|
106
|
+
const firstLine = frame[0].join('')
|
|
102
107
|
console.info(firstLine) // ← Welcome Alice!
|
|
103
108
|
```
|
|
104
109
|
### View Manager
|
|
@@ -115,7 +120,7 @@ How to render frame with View?
|
|
|
115
120
|
```js
|
|
116
121
|
import { View } from '@nan0web/ui'
|
|
117
122
|
const view = new View()
|
|
118
|
-
view.render(1)([
|
|
123
|
+
view.render(1)(['Hello, world'])
|
|
119
124
|
console.info(String(view.frame)) // ← "\rHello, world"
|
|
120
125
|
```
|
|
121
126
|
### Frame Rendering
|
|
@@ -133,13 +138,13 @@ How to create a Frame with fixed size?
|
|
|
133
138
|
```js
|
|
134
139
|
import { Frame } from '@nan0web/ui'
|
|
135
140
|
const frame = new Frame({
|
|
136
|
-
value: [[
|
|
141
|
+
value: [['Frame content']],
|
|
137
142
|
width: 20,
|
|
138
143
|
height: 5,
|
|
139
144
|
renderMethod: Frame.RenderMethod.APPEND,
|
|
140
145
|
})
|
|
141
146
|
const rendered = frame.render()
|
|
142
|
-
console.info(rendered.includes(
|
|
147
|
+
console.info(rendered.includes('Frame content')) // ← true
|
|
143
148
|
```
|
|
144
149
|
### Models
|
|
145
150
|
|
|
@@ -150,7 +155,7 @@ UI models are plain data objects managed by `Model` classes.
|
|
|
150
155
|
How to use a User model?
|
|
151
156
|
```js
|
|
152
157
|
import { Model } from '@nan0web/ui'
|
|
153
|
-
const user = new Model.User({ name:
|
|
158
|
+
const user = new Model.User({ name: 'Charlie', email: 'charlie@example.com' })
|
|
154
159
|
console.info(user.name) // ← Charlie
|
|
155
160
|
console.info(user.email) // ← charlie@example.com
|
|
156
161
|
```
|
|
@@ -164,7 +169,7 @@ with minimal setup.
|
|
|
164
169
|
How to test UI components with assertions?
|
|
165
170
|
```js
|
|
166
171
|
import { Welcome } from '@nan0web/ui'
|
|
167
|
-
const output = Welcome({ user: { name:
|
|
172
|
+
const output = Welcome({ user: { name: 'Test' } })
|
|
168
173
|
console.info(output) // ← Welcome Test!
|
|
169
174
|
```
|
|
170
175
|
## Playground Demos
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nan0web/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "NaN•Web UI. One application logic (algorithm) and many UI.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"test:release": "node --test \"releases/**/*.test.js\"",
|
|
22
22
|
"test:status": "nan0test status --hide-name",
|
|
23
23
|
"test:play": "node --test --test-timeout=3333 \"play/**/*.test.js\"",
|
|
24
|
-
"test:all": "npm run test && npm run test:docs && npm run test:play && npm run build",
|
|
24
|
+
"test:all": "npm run test && npm run test:docs && npm run test:play && npm run build && npm run knip",
|
|
25
|
+
"knip": "knip --production",
|
|
25
26
|
"precommit": "npm test",
|
|
26
27
|
"prepush": "npm test",
|
|
27
28
|
"prepare": "husky",
|
|
@@ -61,13 +62,14 @@
|
|
|
61
62
|
"@nan0web/ui-cli": "1.0.2",
|
|
62
63
|
"@vitest/coverage-v8": "^3.2.4",
|
|
63
64
|
"husky": "^9.1.7",
|
|
65
|
+
"knip": "^5.83.1",
|
|
64
66
|
"vitest": "^3.2.4"
|
|
65
67
|
},
|
|
66
68
|
"dependencies": {
|
|
67
69
|
"@nan0web/co": "^2.0.0",
|
|
68
70
|
"@nan0web/event": "^1.0.0",
|
|
71
|
+
"@nan0web/log": "1.1.1",
|
|
69
72
|
"@nan0web/types": "^1.2.0",
|
|
70
73
|
"string-width": "^7.2.0"
|
|
71
|
-
}
|
|
72
|
-
"peerDependencies": {}
|
|
74
|
+
}
|
|
73
75
|
}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import UiMessage from
|
|
1
|
+
import UiMessage from '../../core/Message/Message.js'
|
|
2
2
|
|
|
3
3
|
class DepsCommandBody {
|
|
4
4
|
fix = false
|
|
5
5
|
static fix = {
|
|
6
|
-
help:
|
|
7
|
-
defaultValue: false
|
|
6
|
+
help: 'Fix dependencies',
|
|
7
|
+
defaultValue: false,
|
|
8
8
|
}
|
|
9
9
|
constructor(input = {}) {
|
|
10
|
-
const {
|
|
11
|
-
fix = this.fix
|
|
12
|
-
} = input
|
|
10
|
+
const { fix = this.fix } = input
|
|
13
11
|
}
|
|
14
12
|
}
|
|
15
13
|
|
|
@@ -18,9 +16,7 @@ export class DepsCommand extends UiMessage {
|
|
|
18
16
|
/** @type {DepsCommandBody} */
|
|
19
17
|
body
|
|
20
18
|
constructor(input = {}) {
|
|
21
|
-
const {
|
|
22
|
-
body = new DepsCommandBody()
|
|
23
|
-
} = UiMessage.parseBody(input, DepsCommandBody)
|
|
19
|
+
const { body = new DepsCommandBody() } = UiMessage.parseBody(input, DepsCommandBody)
|
|
24
20
|
super(input)
|
|
25
21
|
this.body = body
|
|
26
22
|
}
|
package/src/App/Core/CoreApp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Message } from
|
|
2
|
-
import { typeOf } from
|
|
3
|
-
import UI from
|
|
1
|
+
import { Message } from '@nan0web/co'
|
|
2
|
+
import { typeOf } from '@nan0web/types'
|
|
3
|
+
import UI from './UI.js'
|
|
4
4
|
|
|
5
5
|
/** @typedef {Function} CommandFn */
|
|
6
6
|
|
|
@@ -29,11 +29,7 @@ export default class CoreApp {
|
|
|
29
29
|
* @param {Message} [props.startCommand=new Message()] - Command line arguments to parse
|
|
30
30
|
*/
|
|
31
31
|
constructor(props = {}) {
|
|
32
|
-
const {
|
|
33
|
-
name = "CoreApp",
|
|
34
|
-
state = {},
|
|
35
|
-
startCommand = new Message(),
|
|
36
|
-
} = props
|
|
32
|
+
const { name = 'CoreApp', state = {}, startCommand = new Message() } = props
|
|
37
33
|
this.name = String(name)
|
|
38
34
|
this.state = state
|
|
39
35
|
this.commands = new Map()
|
|
@@ -48,7 +44,7 @@ export default class CoreApp {
|
|
|
48
44
|
* @returns {object} Updated state
|
|
49
45
|
*/
|
|
50
46
|
set(state, value) {
|
|
51
|
-
if (
|
|
47
|
+
if ('string' === typeof state) {
|
|
52
48
|
this.state[state] = value
|
|
53
49
|
} else {
|
|
54
50
|
Object.assign(this.state, state)
|
|
@@ -64,7 +60,7 @@ export default class CoreApp {
|
|
|
64
60
|
*/
|
|
65
61
|
registerCommand(commandName, handler) {
|
|
66
62
|
if (!typeOf(Function)(handler)) {
|
|
67
|
-
throw new TypeError(
|
|
63
|
+
throw new TypeError('Handler must be a function')
|
|
68
64
|
}
|
|
69
65
|
this.commands.set(commandName, handler)
|
|
70
66
|
}
|
|
@@ -87,12 +83,17 @@ export default class CoreApp {
|
|
|
87
83
|
async processCommand(msg, ui) {
|
|
88
84
|
const handler = this.commands.get(msg.constructor.name)
|
|
89
85
|
if (!handler) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
throw new Error(
|
|
87
|
+
[
|
|
88
|
+
'Unknown command',
|
|
89
|
+
': ',
|
|
90
|
+
msg.constructor.name,
|
|
91
|
+
'\n',
|
|
92
|
+
'Available commands',
|
|
93
|
+
': ',
|
|
94
|
+
[...this.commands.keys()].join(', '),
|
|
95
|
+
].join(''),
|
|
96
|
+
)
|
|
96
97
|
}
|
|
97
98
|
return await handler.apply(this, [msg, ui])
|
|
98
99
|
}
|
|
@@ -119,6 +120,6 @@ export default class CoreApp {
|
|
|
119
120
|
* @throws {Error} Always thrown as this method must be implemented by subclasses
|
|
120
121
|
*/
|
|
121
122
|
async selectCommand(ui) {
|
|
122
|
-
throw new Error(
|
|
123
|
+
throw new Error('Not implemented, must be implemented by subclass')
|
|
123
124
|
}
|
|
124
125
|
}
|
package/src/App/Core/UI.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Message } from
|
|
2
|
-
import View from
|
|
3
|
-
import CoreApp from
|
|
4
|
-
import Widget from
|
|
1
|
+
import { Message } from '@nan0web/co'
|
|
2
|
+
import View from '../../View/View.js'
|
|
3
|
+
import CoreApp from './CoreApp.js'
|
|
4
|
+
import Widget from './Widget.js'
|
|
5
5
|
|
|
6
6
|
/** @typedef {import("../../View/View.js").ComponentFn} ComponentFn */
|
|
7
7
|
|
|
@@ -31,7 +31,7 @@ export default class UI extends Widget {
|
|
|
31
31
|
* @throws {Error} Always thrown as this method must be implemented by subclasses
|
|
32
32
|
*/
|
|
33
33
|
convertInput(rawInput) {
|
|
34
|
-
throw new Error(
|
|
34
|
+
throw new Error('convertInput must be implemented by subclass')
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -43,16 +43,12 @@ export default class UI extends Widget {
|
|
|
43
43
|
const onStart = () => {
|
|
44
44
|
// this.view.render(UIProcess)
|
|
45
45
|
}
|
|
46
|
-
const onData = () => {
|
|
46
|
+
const onData = () => {}
|
|
47
|
+
const onEnd = () => {}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.on("start", onStart)
|
|
54
|
-
this.on("data", onData)
|
|
55
|
-
this.on("end", onEnd)
|
|
49
|
+
this.on('start', onStart)
|
|
50
|
+
this.on('data', onData)
|
|
51
|
+
this.on('end', onEnd)
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
/**
|
|
@@ -60,7 +56,7 @@ export default class UI extends Widget {
|
|
|
60
56
|
* @param {any[]} results - Results to output
|
|
61
57
|
*/
|
|
62
58
|
output(results) {
|
|
63
|
-
results.forEach(result => {
|
|
59
|
+
results.forEach((result) => {
|
|
64
60
|
this.view.info(JSON.stringify(result))
|
|
65
61
|
})
|
|
66
62
|
}
|
package/src/App/Core/Widget.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import EventProcessor from
|
|
2
|
-
import View from
|
|
3
|
-
import { StreamEntry } from
|
|
4
|
-
import { UiMessage } from
|
|
1
|
+
import EventProcessor from '@nan0web/event/oop'
|
|
2
|
+
import View from '../../View/View.js'
|
|
3
|
+
import { StreamEntry } from '@nan0web/db'
|
|
4
|
+
import { UiMessage } from '../../core/index.js'
|
|
5
5
|
|
|
6
6
|
/** @typedef {import("./UI.js").ComponentFn} ComponentFn */
|
|
7
7
|
|
|
@@ -51,14 +51,10 @@ export default class Widget extends EventProcessor {
|
|
|
51
51
|
*/
|
|
52
52
|
render(viewFnOrName, outputData) {
|
|
53
53
|
/** @type {Function | ComponentFn | undefined} */
|
|
54
|
-
const viewFn = typeof viewFnOrName ===
|
|
55
|
-
? this.view.get(viewFnOrName)
|
|
56
|
-
: viewFnOrName
|
|
54
|
+
const viewFn = typeof viewFnOrName === 'string' ? this.view.get(viewFnOrName) : viewFnOrName
|
|
57
55
|
|
|
58
56
|
if (!viewFn) {
|
|
59
|
-
throw new Error([
|
|
60
|
-
"View component not found", ": ", viewFnOrName
|
|
61
|
-
].join(""))
|
|
57
|
+
throw new Error(['View component not found', ': ', viewFnOrName].join(''))
|
|
62
58
|
}
|
|
63
59
|
return this.view.render(viewFn)(outputData)
|
|
64
60
|
}
|
package/src/App/Core/index.js
CHANGED
package/src/App/Scenario.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import App from
|
|
2
|
-
import UI from
|
|
1
|
+
import App from './index.js'
|
|
2
|
+
import UI from './Core/UI.js'
|
|
3
3
|
|
|
4
4
|
/** @typedef {import("./Core/CoreApp.js").default} CoreApp */
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ export default class Scenario {
|
|
|
19
19
|
*/
|
|
20
20
|
constructor(app, ui) {
|
|
21
21
|
if (!(app instanceof App.Core.App)) {
|
|
22
|
-
throw new TypeError(
|
|
22
|
+
throw new TypeError('Scenario requires a App.Core.App instance')
|
|
23
23
|
}
|
|
24
24
|
this.app = app
|
|
25
25
|
this.ui = ui
|
|
@@ -32,7 +32,7 @@ export default class Scenario {
|
|
|
32
32
|
* @returns {Promise<boolean>} True if all outputs match expected
|
|
33
33
|
*/
|
|
34
34
|
async run(inputCommands, expectedOutputs) {
|
|
35
|
-
const commandMessages = inputCommands.map(arr => App.Command.Message.parse(arr))
|
|
35
|
+
const commandMessages = inputCommands.map((arr) => App.Command.Message.parse(arr))
|
|
36
36
|
const outputs = await this.app.processCommands(commandMessages, this.ui)
|
|
37
37
|
if (outputs.length !== expectedOutputs.length) return false
|
|
38
38
|
for (let i = 0; i < outputs.length; i++) {
|
package/src/App/User/UserApp.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Message } from
|
|
2
|
-
import { notEmpty } from
|
|
3
|
-
import CoreApp from
|
|
4
|
-
import User from
|
|
5
|
-
import UserUI from
|
|
6
|
-
import UserAppCommandMessage from
|
|
7
|
-
import DepsCommand from
|
|
8
|
-
import UIStream from
|
|
9
|
-
import { StreamEntry, UiMessage } from
|
|
1
|
+
import { Message } from '@nan0web/co'
|
|
2
|
+
import { notEmpty } from '@nan0web/types'
|
|
3
|
+
import CoreApp from '../Core/CoreApp.js'
|
|
4
|
+
import User from '../../Model/User/User.js'
|
|
5
|
+
import UserUI from './UserUI.js'
|
|
6
|
+
import UserAppCommandMessage from './Command/Message.js'
|
|
7
|
+
import DepsCommand from './Command/Message.js'
|
|
8
|
+
import UIStream from '../../core/Stream.js'
|
|
9
|
+
import { StreamEntry, UiMessage } from '../../core/index.js'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* UserApp requires user name and shows Welcome view.
|
|
@@ -20,9 +20,9 @@ export default class UserApp extends CoreApp {
|
|
|
20
20
|
*/
|
|
21
21
|
constructor(props = {}) {
|
|
22
22
|
super(props)
|
|
23
|
-
this.registerCommand(
|
|
24
|
-
this.registerCommand(
|
|
25
|
-
this.registerCommand(
|
|
23
|
+
this.registerCommand('setUser', this.setUser.bind(this))
|
|
24
|
+
this.registerCommand('welcome', this.welcome.bind(this))
|
|
25
|
+
this.registerCommand('deps', this.handleDeps.bind(this)) // Register new command
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -33,12 +33,18 @@ export default class UserApp extends CoreApp {
|
|
|
33
33
|
*/
|
|
34
34
|
async handleDeps(cmd, ui) {
|
|
35
35
|
// Example: Use async generator to stream deps processing
|
|
36
|
-
const processorFn = async () =>
|
|
36
|
+
const processorFn = async () =>
|
|
37
|
+
new StreamEntry({
|
|
38
|
+
value: { message: `Deps command executed with fix: ${cmd.body.fix}` },
|
|
39
|
+
done: true,
|
|
40
|
+
})
|
|
37
41
|
const generatorFn = UIStream.createProcessor(new AbortController().signal, processorFn)
|
|
38
|
-
await UIStream.process(
|
|
42
|
+
await UIStream.process(
|
|
43
|
+
new AbortController().signal,
|
|
44
|
+
generatorFn,
|
|
39
45
|
(progress, item) => ui.output && ui.output(item.value), // Fix to output the value
|
|
40
46
|
(error) => ui.output && ui.output([error]), // Assume ui has output method
|
|
41
|
-
(item) => ui.output && ui.output(item.value) // Fix complete callback
|
|
47
|
+
(item) => ui.output && ui.output(item.value), // Fix complete callback
|
|
42
48
|
)
|
|
43
49
|
return { completed: true }
|
|
44
50
|
}
|
|
@@ -53,7 +59,7 @@ export default class UserApp extends CoreApp {
|
|
|
53
59
|
this.state.user = User.from(cmd.body.user) // cmd is UserAppCommandMessage, has user
|
|
54
60
|
const frame = await this.welcome(cmd, ui)
|
|
55
61
|
return {
|
|
56
|
-
message: String(frame)
|
|
62
|
+
message: String(frame),
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
|
|
@@ -64,15 +70,16 @@ export default class UserApp extends CoreApp {
|
|
|
64
70
|
* @returns {Promise<string[][]>} Welcome view output
|
|
65
71
|
*/
|
|
66
72
|
async welcome(cmd, ui) {
|
|
67
|
-
if (cmd.body.user) {
|
|
73
|
+
if (cmd.body.user) {
|
|
74
|
+
// cmd is UserAppCommandMessage, has user
|
|
68
75
|
const user = User.from(cmd.body.user)
|
|
69
|
-
return ui.render(
|
|
76
|
+
return ui.render('Welcome', { user })
|
|
70
77
|
}
|
|
71
78
|
if (notEmpty(this.user)) {
|
|
72
|
-
return ui.render(
|
|
79
|
+
return ui.render('Welcome', { user: this.user })
|
|
73
80
|
}
|
|
74
|
-
const answer = await ui.ask(UiMessage.from(
|
|
81
|
+
const answer = await ui.ask(UiMessage.from('What is your name?'))
|
|
75
82
|
this.user = User.from(answer?.body)
|
|
76
|
-
return ui.render(
|
|
83
|
+
return ui.render('Welcome', { user: this.user })
|
|
77
84
|
}
|
|
78
85
|
}
|
package/src/App/User/UserUI.js
CHANGED
package/src/App/User/index.js
CHANGED
package/src/App/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import Scenario from
|
|
2
|
-
import UI from
|
|
1
|
+
import Scenario from './Scenario.js'
|
|
2
|
+
import UI from './Core/UI.js'
|
|
3
3
|
|
|
4
|
-
import Core from
|
|
5
|
-
import User from
|
|
4
|
+
import Core from './Core/index.js'
|
|
5
|
+
import User from './User/index.js'
|
|
6
6
|
|
|
7
|
-
export {
|
|
8
|
-
Core,
|
|
9
|
-
User,
|
|
10
|
-
Scenario,
|
|
11
|
-
UI,
|
|
12
|
-
}
|
|
7
|
+
export { Core, User, Scenario, UI }
|
|
13
8
|
|
|
14
9
|
export default {
|
|
15
10
|
Core,
|
|
@@ -5,22 +5,22 @@
|
|
|
5
5
|
class ProcessInput {
|
|
6
6
|
/** @type {string} Process name to display */
|
|
7
7
|
name
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
/** @type {number} Current progress index */
|
|
10
10
|
i
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
/** @type {number} Top limit for progress normalization */
|
|
13
13
|
top
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
/** @type {number} Width of the progress bar */
|
|
16
16
|
width
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
/** @type {string} Character to use for empty space */
|
|
19
19
|
space
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
/** @type {string} Character to use for filled progress */
|
|
22
22
|
char
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
/**
|
|
25
25
|
* Creates a new ProcessInput instance.
|
|
26
26
|
* @param {object} props - Process input properties
|
|
@@ -32,14 +32,7 @@ class ProcessInput {
|
|
|
32
32
|
* @param {string} [props.char='*'] - Character for filled progress
|
|
33
33
|
*/
|
|
34
34
|
constructor(props = {}) {
|
|
35
|
-
const {
|
|
36
|
-
name = "NaN•Coding",
|
|
37
|
-
i = 0,
|
|
38
|
-
top = 9,
|
|
39
|
-
width = 9,
|
|
40
|
-
space = '•',
|
|
41
|
-
char = '*'
|
|
42
|
-
} = props
|
|
35
|
+
const { name = 'NaN•Coding', i = 0, top = 9, width = 9, space = '•', char = '*' } = props
|
|
43
36
|
this.name = name
|
|
44
37
|
this.i = i
|
|
45
38
|
this.top = top
|
|
@@ -47,7 +40,7 @@ class ProcessInput {
|
|
|
47
40
|
this.space = space
|
|
48
41
|
this.char = char
|
|
49
42
|
}
|
|
50
|
-
|
|
43
|
+
|
|
51
44
|
/**
|
|
52
45
|
* Converts the input to a string representation.
|
|
53
46
|
* @returns {string} String representation of the ProcessInput
|
|
@@ -55,7 +48,7 @@ class ProcessInput {
|
|
|
55
48
|
toString() {
|
|
56
49
|
return `ProcessInput(name=${this.name}, i=${this.i}, top=${this.top}, width=${this.width}, space=${this.space}, char=${this.char})`
|
|
57
50
|
}
|
|
58
|
-
|
|
51
|
+
|
|
59
52
|
/**
|
|
60
53
|
* Creates a ProcessInput instance from the given props.
|
|
61
54
|
* @param {ProcessInput|object} props - The properties to create from
|
|
@@ -67,4 +60,4 @@ class ProcessInput {
|
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
|
|
70
|
-
export default ProcessInput
|
|
63
|
+
export default ProcessInput
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import ProcessInput from
|
|
2
|
-
import View from
|
|
1
|
+
import ProcessInput from './Input.js'
|
|
2
|
+
import View from '../../View/View.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Renders a progress bar based on input configuration.
|
|
@@ -16,9 +16,7 @@ function Process(props = {}) {
|
|
|
16
16
|
// Provide empty options object to satisfy Locale.format signature
|
|
17
17
|
const format = this.locale.format(Number, {})
|
|
18
18
|
const num = format ? format(100 * per) : 100 * per
|
|
19
|
-
return [
|
|
20
|
-
[`I am ${input.name} ${bar} ${num}`]
|
|
21
|
-
]
|
|
19
|
+
return [[`I am ${input.name} ${bar} ${num}`]]
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
Process.Input = ProcessInput
|