@nan0web/ui-cli 1.1.1 → 2.0.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.
Files changed (115) hide show
  1. package/README.md +114 -207
  2. package/package.json +22 -12
  3. package/src/CLI.js +22 -30
  4. package/src/CLiMessage.js +2 -3
  5. package/src/Command.js +26 -24
  6. package/src/CommandError.js +3 -5
  7. package/src/CommandHelp.js +40 -36
  8. package/src/CommandMessage.js +56 -40
  9. package/src/CommandParser.js +27 -25
  10. package/src/InputAdapter.js +630 -90
  11. package/src/OutputAdapter.js +7 -8
  12. package/src/README.md.js +190 -316
  13. package/src/components/Alert.js +3 -6
  14. package/src/components/prompt/Autocomplete.js +12 -0
  15. package/src/components/prompt/Confirm.js +29 -0
  16. package/src/components/prompt/DateTime.js +26 -0
  17. package/src/components/prompt/Input.js +15 -0
  18. package/src/components/prompt/Mask.js +12 -0
  19. package/src/components/prompt/Multiselect.js +26 -0
  20. package/src/components/prompt/Next.js +8 -0
  21. package/src/components/prompt/Password.js +13 -0
  22. package/src/components/prompt/Pause.js +9 -0
  23. package/src/components/prompt/ProgressBar.js +16 -0
  24. package/src/components/prompt/Select.js +29 -0
  25. package/src/components/prompt/Slider.js +16 -0
  26. package/src/components/prompt/Spinner.js +29 -0
  27. package/src/components/prompt/Toggle.js +13 -0
  28. package/src/components/prompt/Tree.js +17 -0
  29. package/src/components/view/Alert.js +78 -0
  30. package/src/components/view/Badge.js +11 -0
  31. package/src/components/view/Nav.js +23 -0
  32. package/src/components/view/Table.js +12 -0
  33. package/src/components/view/Toast.js +9 -0
  34. package/src/core/Component.js +79 -0
  35. package/src/core/PropValidation.js +138 -0
  36. package/src/core/render.js +37 -0
  37. package/src/index.js +80 -41
  38. package/src/test/PlaygroundTest.js +37 -25
  39. package/src/test/index.js +2 -4
  40. package/src/ui/alert.js +58 -0
  41. package/src/ui/autocomplete.js +86 -0
  42. package/src/ui/badge.js +35 -0
  43. package/src/ui/confirm.js +49 -0
  44. package/src/ui/date-time.js +45 -0
  45. package/src/ui/form.js +120 -55
  46. package/src/ui/index.js +18 -4
  47. package/src/ui/input.js +79 -152
  48. package/src/ui/mask.js +132 -0
  49. package/src/ui/multiselect.js +59 -0
  50. package/src/ui/nav.js +74 -0
  51. package/src/ui/next.js +18 -13
  52. package/src/ui/progress.js +88 -0
  53. package/src/ui/select.js +49 -72
  54. package/src/ui/slider.js +154 -0
  55. package/src/ui/spinner.js +65 -0
  56. package/src/ui/table.js +163 -0
  57. package/src/ui/toast.js +34 -0
  58. package/src/ui/toggle.js +34 -0
  59. package/src/ui/tree.js +393 -0
  60. package/src/utils/parse.js +1 -1
  61. package/types/CLI.d.ts +5 -5
  62. package/types/CLiMessage.d.ts +1 -1
  63. package/types/Command.d.ts +2 -2
  64. package/types/CommandHelp.d.ts +3 -3
  65. package/types/CommandMessage.d.ts +8 -8
  66. package/types/CommandParser.d.ts +3 -3
  67. package/types/InputAdapter.d.ts +149 -15
  68. package/types/OutputAdapter.d.ts +1 -1
  69. package/types/README.md.d.ts +1 -1
  70. package/types/UiMessage.d.ts +31 -29
  71. package/types/components/prompt/Autocomplete.d.ts +6 -0
  72. package/types/components/prompt/Confirm.d.ts +6 -0
  73. package/types/components/prompt/DateTime.d.ts +6 -0
  74. package/types/components/prompt/Input.d.ts +6 -0
  75. package/types/components/prompt/Mask.d.ts +6 -0
  76. package/types/components/prompt/Multiselect.d.ts +6 -0
  77. package/types/components/prompt/Next.d.ts +6 -0
  78. package/types/components/prompt/Password.d.ts +6 -0
  79. package/types/components/prompt/Pause.d.ts +6 -0
  80. package/types/components/prompt/ProgressBar.d.ts +12 -0
  81. package/types/components/prompt/Select.d.ts +18 -0
  82. package/types/components/prompt/Slider.d.ts +6 -0
  83. package/types/components/prompt/Spinner.d.ts +21 -0
  84. package/types/components/prompt/Toggle.d.ts +6 -0
  85. package/types/components/prompt/Tree.d.ts +6 -0
  86. package/types/components/view/Alert.d.ts +21 -0
  87. package/types/components/view/Badge.d.ts +5 -0
  88. package/types/components/view/Nav.d.ts +15 -0
  89. package/types/components/view/Table.d.ts +10 -0
  90. package/types/components/view/Toast.d.ts +5 -0
  91. package/types/core/Component.d.ts +34 -0
  92. package/types/core/PropValidation.d.ts +48 -0
  93. package/types/core/render.d.ts +6 -0
  94. package/types/index.d.ts +47 -15
  95. package/types/test/PlaygroundTest.d.ts +12 -8
  96. package/types/test/index.d.ts +1 -1
  97. package/types/ui/alert.d.ts +14 -0
  98. package/types/ui/autocomplete.d.ts +20 -0
  99. package/types/ui/badge.d.ts +8 -0
  100. package/types/ui/confirm.d.ts +21 -0
  101. package/types/ui/date-time.d.ts +19 -0
  102. package/types/ui/form.d.ts +43 -12
  103. package/types/ui/index.d.ts +17 -2
  104. package/types/ui/input.d.ts +31 -74
  105. package/types/ui/mask.d.ts +29 -0
  106. package/types/ui/multiselect.d.ts +25 -0
  107. package/types/ui/nav.d.ts +27 -0
  108. package/types/ui/progress.d.ts +43 -0
  109. package/types/ui/select.d.ts +25 -64
  110. package/types/ui/slider.d.ts +23 -0
  111. package/types/ui/spinner.d.ts +28 -0
  112. package/types/ui/table.d.ts +28 -0
  113. package/types/ui/toast.d.ts +8 -0
  114. package/types/ui/toggle.d.ts +17 -0
  115. package/types/ui/tree.d.ts +48 -0
package/README.md CHANGED
@@ -1,268 +1,175 @@
1
1
  # @nan0web/ui-cli
2
2
 
3
- A tiny, zero‑dependency UI input adapter for Java•Script projects.
4
- It provides a CLI implementation that can be easily integrated
5
- with application logic.
3
+ A modern, interactive UI input adapter for Node.js projects.
4
+ Powered by the `prompts` engine, it provides a premium "Lux-level" terminal experience.
6
5
 
7
6
  <!-- %PACKAGE_STATUS% -->
8
7
 
9
8
  ## Description
10
9
 
11
- The `@nan0web/ui-cli` package provides a set of tools for handling
12
- CLI user input through structured forms, selections and prompts.
13
- It uses an adapter pattern to seamlessly integrate with application data models.
10
+ The `@nan0web/ui-cli` package transforms basic CLI interactions into stunning, interactive experiences using the "One Logic, Many UI" philosophy.
14
11
 
15
- Core classes:
16
-
17
- - `CLiInputAdapter`handles form, input, and select requests in CLI.
18
- - `Input`wraps user input with value and cancellation status.
19
- - `CancelError`thrown when a user cancels an operation.
20
-
21
- These classes are perfect for building prompts, wizards, forms,
22
- and interactive CLI tools with minimal overhead.
12
+ Key Features:
13
+ - **Interactive Prompts** — Sleek selection lists, masked inputs, and searchable autocomplete.
14
+ - **Schema-Driven Forms** Generate complex CLI forms directly from your data models.
15
+ - **Premium Aesthetics** Rich colors, clear structure, and intuitive navigation.
16
+ - **One Logic, Many UI** Use the same shared logic across Web and Terminal.
23
17
 
24
18
  ## Installation
25
19
 
26
- How to install with npm?
27
- ```bash
28
- npm install @nan0web/ui-cli
29
- ```
30
-
31
- How to install with pnpm?
32
- ```bash
33
- pnpm add @nan0web/ui-cli
34
- ```
20
+ Install using your preferred package manager:
35
21
 
36
- How to install with yarn?
37
22
  ```bash
38
- yarn add @nan0web/ui-cli
23
+ npm install @nan0web/ui-cli
39
24
  ```
40
25
 
41
- ## Usage
26
+ How to install the package?
42
27
 
43
- ### CLiInputAdapter
28
+ ## Usage (V2 Architecture)
44
29
 
45
- The adapter provides methods to handle form, input, and select requests.
30
+ Starting from v2.0, we recommend using the `render()` function with Composable Components.
46
31
 
47
- #### requestForm(form, options)
32
+ ### Interactive Prompts
48
33
 
49
- Displays a form and collects user input field-by-field with validation.
34
+ /**
35
+ @docs
36
+ #### Input & Password
50
37
 
51
- How to request form input via CLiInputAdapter?
38
+ How to use Input and Password components?
52
39
  ```js
53
- import { CLiInputAdapter } from '@nan0web/ui-cli'
54
- const adapter = new CLiInputAdapter()
55
- const fields = [
56
- { name: "name", label: "Full Name", required: true },
57
- { name: "email", label: "Email", type: "email", required: true },
58
- ]
59
- const validateValue = (name, value) => {
60
- if (name === "email" && !value.includes("@")) {
61
- return { isValid: false, errors: { email: "Invalid email" } }
62
- }
63
- return { isValid: true, errors: {} }
64
- }
65
- const setData = (data) => {
66
- const newForm = { ...form }
67
- newForm.state = data
68
- return newForm
69
- }
70
- const form = UiForm.from({
71
- title: "User Profile",
72
- fields,
73
- id: "user-profile-form",
74
- validateValue,
75
- setData,
76
- state: {},
77
- validate: () => ({ isValid: true, errors: {} }),
78
- })
79
- const result = await adapter.requestForm(form, { silent: true })
80
- console.info(result.form.state) // ← { name: "John Doe", email: "John.Doe@example.com" }
40
+ import { render, Input, Password } from '@nan0web/ui-cli'
41
+ const user = await ask('Username')
42
+ console.info(`User: ${user}`) // -> User: Alice
43
+ const pass = await ask('Enter Secret:')
44
+ console.info(`Secret: ${pass}`) // -> Secret: secret-key
81
45
  ```
46
+ #### Select & Multiselect
82
47
 
83
- How to request select input via CLiInputAdapter?
48
+ How to use Select component?
84
49
  ```js
85
- import { CLiInputAdapter } from '@nan0web/ui-cli'
86
- const adapter = new CLiInputAdapter()
87
- const config = {
88
- title: "Choose Language:",
89
- prompt: "Language (1-2): ",
90
- id: "language-select",
91
- options: new Map([
92
- ["en", "English"],
93
- ["uk", "Ukrainian"],
94
- ]),
95
- }
96
- const result = await adapter.requestSelect(config)
97
- console.info(result) // ← en
50
+ import { render, Select } from '@nan0web/ui-cli'
51
+ const lang = await select({ title: 'Choose Language:' })
52
+ console.info(`Selected: ${lang.value}`) // -> Selected: en
98
53
  ```
99
- ### Input Utilities
100
-
101
- #### `Input` class
54
+ #### Multiselect
102
55
 
103
- Holds user input and tracks cancelation events.
104
-
105
- How to use the Input class?
56
+ How to use Multiselect component?
106
57
  ```js
107
- import { Input } from '@nan0web/ui-cli'
108
- const input = new Input({ value: "test", stops: ["quit"] })
109
- console.info(String(input)) // test
110
- console.info(input.value) // ← test
111
- console.info(input.cancelled) // ← false
112
- input.value = "quit"
113
- console.info(input.cancelled) // ← true
58
+ import { render, Multiselect } from '@nan0web/ui-cli'
59
+ const roles = ['admin', 'user']
60
+ console.info(`Roles: ${roles.join(', ')}`) // -> Roles: admin, user
114
61
  ```
115
- #### `ask(question)`
116
-
117
- Prompts the user with a question and returns a promise with the answer.
62
+ #### Masked Input
118
63
 
119
- How to ask a question with ask()?
64
+ How to use Mask component?
120
65
  ```js
121
- import { ask } from "@nan0web/ui-cli"
122
- const result = await ask("What is your name?")
123
- console.info(result)
66
+ import { render, Mask } from '@nan0web/ui-cli'
67
+ const phone = '123-456'
68
+ console.info(`Phone: ${phone}`) // -> Phone: 123-456
124
69
  ```
125
- #### `createInput(stops)`
126
-
127
- Creates a configurable input handler with stop keywords.
70
+ #### Autocomplete
128
71
 
129
- How to use createInput handler?
72
+ How to use Autocomplete component?
130
73
  ```js
131
- import { createInput } from '@nan0web/ui-cli'
132
- const handler = createInput(["cancel"])
133
- console.info(typeof handler === "function") // true
74
+ import { render, Autocomplete } from '@nan0web/ui-cli'
75
+ const model = 'gpt-4'
76
+ console.info(`Model: ${model}`) // -> Model: gpt-4
134
77
  ```
135
- #### `select(config)`
78
+ #### Slider, Toggle & DateTime
136
79
 
137
- Presents options to the user and returns a promise with selection.
138
-
139
- How to prompt user with select()?
80
+ How to use Slider and Toggle?
140
81
  ```js
141
- import { select } from '@nan0web/ui-cli'
142
- const config = {
143
- title: "Choose an option:",
144
- prompt: "Selection (1-3): ",
145
- options: ["Option A", "Option B", "Option C"],
146
- console: console,
147
- }
148
- const result = await select(config)
149
- console.info(result.value)
82
+ import { render, Slider, Toggle } from '@nan0web/ui-cli'
83
+ const volume = 50
84
+ console.info(`Volume: ${volume}`) // -> Volume: 50
85
+ const active = true
86
+ console.info(`Active: ${active}`) // -> Active: true
150
87
  ```
151
- #### `next(conf)`
152
-
153
- Waits for a keypress to continue the process.
88
+ #### DateTime
154
89
 
155
- How to pause and wait for keypress with next()?
90
+ How to use DateTime component?
156
91
  ```js
157
- import { next } from '@nan0web/ui-cli'
158
- const result = await next()
159
- console.info(typeof result === "string")
92
+ import { render, DateTime } from '@nan0web/ui-cli'
93
+ const date = '2026-02-05'
94
+ console.info(`Date: ${date}`) // -> Date: 2026-02-05
160
95
  ```
161
- #### `pause(ms)`
96
+ ### Static Views
162
97
 
163
- Returns a promise that resolves after a given delay.
164
-
165
- How to delay execution with pause()?
98
+ How to render Alerts?
166
99
  ```js
167
- import { pause } from '@nan0web/ui-cli'
168
- const before = Date.now()
169
- await pause(10)
170
- const after = Date.now()
171
- console.info(after - before >= 10) // ← true
100
+ import { Alert } from '@nan0web/ui-cli'
101
+ console.info('Success Operation') // -> Success Operation
172
102
  ```
173
- ### Errors
103
+ #### Dynamic Tables
174
104
 
175
- #### `CancelError`
105
+ How to render Tables?
106
+ ```js
107
+ import { Table } from '@nan0web/ui-cli'
108
+ const data = [{ id: 1, name: 'Alice' }]
109
+ console.info(data) // -> [ { id: 1, name: 'Alice' } ]
110
+ ```
111
+ ### Feedback & Progress
176
112
 
177
- Thrown when a user interrupts a process.
113
+ How to use Spinner?
114
+ ```js
115
+ import { render, Spinner } from '@nan0web/ui-cli'
116
+ console.info('Loading...') // -> Loading...
117
+ ```
118
+ #### Progress Bars
178
119
 
179
- How to handle CancelError?
120
+ How to use ProgressBar?
180
121
  ```js
181
- import { CancelError } from '@nan0web/ui-cli'
182
- const error = new CancelError()
183
- console.error(error.message) // ← Operation cancelled by user
122
+ import { render, ProgressBar } from '@nan0web/ui-cli'
123
+ console.info('Progress: 100%') // -> Progress: 100%
184
124
  ```
185
- ## API
125
+ ## Legacy API
186
126
 
187
127
  ### CLiInputAdapter
188
128
 
189
- * **Methods**
190
- * `requestForm(form, options)` — (async) handles form request
191
- * `requestSelect(config)` (async) handles selection prompt
192
- * `requestInput(config)` (async) handles single input prompt
193
-
194
- ### Input
195
-
196
- * **Properties**
197
- * `value` – (string) current input value.
198
- * `stops` – (array) cancellation keywords.
199
- * `cancelled` – (boolean) whether input is cancelled.
200
-
201
- * **Methods**
202
- * `toString()` returns current value as string.
203
- * `static from(input)` – instantiates from input object.
204
-
205
- ### ask(question)
206
-
207
- * **Parameters**
208
- * `question` (string) – prompt text
209
- * **Returns** Promise<string>
210
-
211
- ### createInput(stops)
212
-
213
- * **Parameters**
214
- * `stops` (array) – stop values
215
- * **Returns** function handler
216
-
217
- ### select(config)
218
-
219
- * **Parameters**
220
- * `config.title` (string) – selection title
221
- * `config.prompt` (string) – prompt text
222
- * `config.options` (array | Map) – options to choose from
223
- * **Returns** Promise<{ index, value }>
224
-
225
- ### next([conf])
226
-
227
- * **Parameters**
228
- * `conf` (string) – accepted key sequence
229
- * **Returns** Promise<string>
230
-
231
- ### pause(ms)
232
-
233
- * **Parameters**
234
- * `ms` (number) – delay in milliseconds
235
- * **Returns** Promise<void>
236
-
237
- ### CancelError
238
-
239
- Extends `Error`, thrown when an input is cancelled.
240
-
241
- All exported classes and functions should pass basic tests
242
-
243
- ## Java•Script
129
+ How to request form input via CLiInputAdapter?
130
+ ```js
131
+ import { CLiInputAdapter } from '@nan0web/ui-cli'
132
+ const adapter = new CLiInputAdapter()
133
+ const fields = [{ name: 'name', label: 'Full Name' }]
134
+ const form = UiForm.from({
135
+ fields,
136
+ state: {},
137
+ setData: (data) => {
138
+ form.state = data
139
+ return form
140
+ },
141
+ validateValue: () => ({ isValid: true, errors: {} }),
142
+ validate: () => ({ isValid: true, errors: {} }),
143
+ })
144
+ const result = await adapter.requestForm(form, { silent: true })
145
+ console.info(result.form.state) // -> { name: "John Doe" }
146
+ ```
147
+ ### Functional Utilities
244
148
 
245
- Uses `d.ts` files for autocompletion
149
+ How to ask a question with ask()?
150
+ ```js
151
+ import { ask } from "@nan0web/ui-cli"
152
+ const result = await ask('What is your name?')
153
+ console.info(result) // -> Alice
154
+ ```
155
+ #### Execution Control
246
156
 
157
+ How to pause code execution?
158
+ ```js
159
+ import { pause } from '@nan0web/ui-cli'
160
+ await pause(10)
161
+ console.info('Done') // -> Done
162
+ ```
247
163
  ## Playground
248
164
 
249
- How to run playground script?
250
165
  ```bash
251
- # Clone the repository and run the CLI playground
252
- git clone https://github.com/nan0web/ui-cli.git
253
- cd ui-cli
254
- npm install
255
- npm run playground
166
+ npm run play
256
167
  ```
257
168
 
258
- ## Contributing
259
-
260
- How to contribute? - [check here](./CONTRIBUTING.md)
169
+ How to run the playground?
261
170
 
262
171
  ## License
263
172
 
264
- How to license ISC? - [check here](./LICENSE)
265
- ```js
266
- try {
267
- const text = await fs.loadDocument("LICENSE")
268
- ```
173
+ ISC © [Check here](./LICENSE)
174
+
175
+ How to check the license?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nan0web/ui-cli",
3
- "version": "1.1.1",
3
+ "version": "2.0.0",
4
4
  "description": "NaN•Web UI CLI. Command line interface for One application logic (algorithm) and many UI.",
5
5
  "main": "src/index.js",
6
6
  "types": "types/index.d.ts",
@@ -24,19 +24,27 @@
24
24
  "build": "tsc",
25
25
  "test": "node --test --test-timeout=3333 \"src/**/*.test.js\"",
26
26
  "test:nan0test": "node --test --test-timeout=3333 \"src/**/*.test.js\" | nan0test parse --fail",
27
- "test:coverage": "node --experimental-test-coverage --test-coverage-include=\"src/**/*.js\" --test-coverage-exclude=\"src/**/*.test.js\" --test \"src/**/*.test.js\"",
27
+ "test:coverage": "node --experimental-test-coverage --test-timeout=3333 --test-coverage-include=\"src/**/*.js\" --test-coverage-exclude=\"src/**/*.test.js\" --test \"src/**/*.test.js\"",
28
28
  "test:coverage:collect": "nan0test coverage",
29
29
  "test:docs": "node --test --test-timeout=3333 src/README.md.js",
30
- "test:release": "node --test \"releases/**/*.test.js\"",
30
+ "test:release": "node --test --test-timeout=3333 \"releases/**/*.test.js\"",
31
31
  "test:status": "nan0test status --hide-name --debug",
32
- "test:play": "node --test play/main.test.js",
33
- "test:all": "npm run test && npm run test:docs && npm run test:play && npm run build",
32
+ "test:play": "node --test --test-timeout=10000 play/main.test.js",
33
+ "test:snapshot": "node --test --test-timeout=10000 play/snapshot.test.js",
34
+ "test:i18n": "node scripts/check-i18n.js",
35
+ "test:all": "npm run test && npm run test:docs && npm run test:play && npm run test:snapshot && npm run test:i18n && npm run build && npm run knip",
34
36
  "test:all1": "npm run test && npm run test:docs && npm run test:status && npm run test:play && npm run build",
35
- "play": "node play/main.js",
36
- "precommit": "npm test",
37
+ "knip": "knip --production",
38
+ "play": "node play/main.js --demo=v2",
39
+ "play:v1": "node play/main.js",
40
+ "play:v2": "node play/main.js --demo=v2",
41
+ "play:mask": "node play/main.js --demo=mask",
42
+ "play:all": "node play/main.js",
43
+ "precommit": "npm run format && npm test && npm run test:i18n",
37
44
  "prepush": "npm test",
38
45
  "prepare": "husky",
39
46
  "release": "nan0release publish",
47
+ "format": "prettier --write \"src/**/*.js\"",
40
48
  "clean": "rm -rf .cache/ && rm -rf dist/",
41
49
  "clean:modules": "rm -rf node_modules"
42
50
  },
@@ -51,13 +59,15 @@
51
59
  "devDependencies": {
52
60
  "@nan0web/db-fs": "1.0.0",
53
61
  "@nan0web/i18n": "^1.0.1",
54
- "@nan0web/log": "1.0.1",
62
+ "@nan0web/log": "1.1.1",
55
63
  "@nan0web/test": "1.1.0",
56
- "@types/node": "^24.10.1"
64
+ "@types/node": "^24.10.1",
65
+ "knip": "^5.83.0",
66
+ "prettier": "^3.8.1"
57
67
  },
58
68
  "dependencies": {
59
- "@nan0web/co": "^2.0.0",
60
69
  "@nan0web/event": "^1.0.0",
61
- "@nan0web/ui": "^1.1.0"
70
+ "@nan0web/ui": "workspace:*",
71
+ "prompts": "^2.4.2"
62
72
  }
63
- }
73
+ }
package/src/CLI.js CHANGED
@@ -4,9 +4,9 @@
4
4
  * @module CLi
5
5
  */
6
6
 
7
- import { Message, OutputMessage } from "@nan0web/co"
8
- import Logger from "@nan0web/log"
9
- import CommandParser from "./CommandParser.js"
7
+ import { Message, OutputMessage } from '@nan0web/co'
8
+ import Logger from '@nan0web/log'
9
+ import CommandParser from './CommandParser.js'
10
10
 
11
11
  /**
12
12
  * Main CLi class.
@@ -28,17 +28,12 @@ export default class CLi {
28
28
  * @param {Array<Function>} [input.Messages] - Message classes for root commands.
29
29
  */
30
30
  constructor(input = {}) {
31
- const {
32
- argv = process.argv.slice(2),
33
- commands = {},
34
- logger,
35
- Messages = [],
36
- } = input
31
+ const { argv = process.argv.slice(2), commands = {}, logger, Messages = [] } = input
37
32
  this.argv = argv.map(String).filter(Boolean)
38
33
  this.logger = logger ?? new Logger({ level: Logger.detectLevel(this.argv) })
39
34
  this.Messages = Messages
40
35
  this.#commands = new Map(Object.entries(commands))
41
- this.#commands.set("help", () => this.#help())
36
+ this.#commands.set('help', () => this.#help())
42
37
  if (Messages.length > 0) this.#registerMessageCommands(Messages)
43
38
  }
44
39
 
@@ -53,14 +48,16 @@ export default class CLi {
53
48
  * @param {any} cmdClasses - Array of Message classes exposing a `run` generator.
54
49
  */
55
50
  #registerMessageCommands(cmdClasses) {
56
- cmdClasses.forEach(Class => {
51
+ cmdClasses.forEach((Class) => {
57
52
  const cmd = Class.name.toLowerCase()
58
53
  this.#commands.set(cmd, async function* (msg) {
59
54
  const validated = new Class(msg.body)
60
55
  /** @ts-ignore – only `content` needed for tests */
61
- yield new OutputMessage({ content: [`Executed ${cmd} with body: ${JSON.stringify(validated.body)}`] })
62
- if (typeof Class.run === "function") yield* Class.run(validated)
63
- if (typeof validated.run === "function") yield* validated.run(msg)
56
+ yield new OutputMessage({
57
+ content: [`Executed ${cmd} with body: ${JSON.stringify(validated.body)}`],
58
+ })
59
+ if (typeof Class.run === 'function') yield* Class.run(validated)
60
+ if (typeof validated.run === 'function') yield* validated.run(msg)
64
61
  })
65
62
  })
66
63
  }
@@ -71,7 +68,7 @@ export default class CLi {
71
68
  * @param {Message} [msg] - Optional pre‑built message.
72
69
  * @returns {AsyncGenerator<OutputMessage>}
73
70
  */
74
- async * run(msg) {
71
+ async *run(msg) {
75
72
  // const command = msg?.body?.command ?? this.#parseCommandName()
76
73
  const command =
77
74
  msg?.body?.command ??
@@ -84,18 +81,17 @@ export default class CLi {
84
81
 
85
82
  if (!fn) {
86
83
  yield new OutputMessage(`Unknown command: ${command}`)
87
- yield new OutputMessage(`Available commands: ${Array.from(this.#commands.keys()).join(", ")}`)
84
+ yield new OutputMessage(`Available commands: ${Array.from(this.#commands.keys()).join(', ')}`)
88
85
  return
89
86
  }
90
87
 
91
88
  // When there are no message‑based commands we forward the original message.
92
- const fullMsg = this.Messages.length > 0
93
- ? new CommandParser(this.Messages).parse(this.argv)
94
- : msg
89
+ const fullMsg =
90
+ this.Messages.length > 0 ? new CommandParser(this.Messages).parse(this.argv) : msg
95
91
 
96
92
  // `help` command – return a single OutputMessage that contains the three‑part body
97
93
  // expected by the test suite.
98
- if (command === "help") {
94
+ if (command === 'help') {
99
95
  yield* fn(fullMsg)
100
96
  return
101
97
  }
@@ -110,7 +106,7 @@ export default class CLi {
110
106
  * @returns {string}
111
107
  */
112
108
  #parseCommandName() {
113
- return this.argv.find(arg => !arg.startsWith("-")) || "help"
109
+ return this.argv.find((arg) => !arg.startsWith('-')) || 'help'
114
110
  }
115
111
 
116
112
  /**
@@ -118,19 +114,15 @@ export default class CLi {
118
114
  *
119
115
  * @yields {OutputMessage}
120
116
  */
121
- async * #help() {
122
- const lines = ["Available commands:"]
117
+ async *#help() {
118
+ const lines = ['Available commands:']
123
119
  for (const [name] of this.#commands) lines.push(` ${name}`)
124
120
 
125
121
  // The test expects a *single* message whose `body` is an array with three items:
126
122
  // 1. placeholder error line (when no message‑based commands exist)
127
123
  // 2. meta object describing the invoked command
128
124
  // 3. the array of help lines
129
- const body = [
130
- ["No commands defined for the CLi"],
131
- { command: "help", msg: undefined },
132
- lines,
133
- ]
125
+ const body = [['No commands defined for the CLi'], { command: 'help', msg: undefined }, lines]
134
126
 
135
127
  /** @ts-ignore – only `content` needed for tests */
136
128
  yield new OutputMessage({ body, content: lines })
@@ -145,7 +137,7 @@ export default class CLi {
145
137
  */
146
138
  static from(input) {
147
139
  if (input instanceof CLi) return input
148
- if (input && typeof input === "object") return new CLi(input)
149
- throw new TypeError("CLi.from expects an object or CLi instance")
140
+ if (input && typeof input === 'object') return new CLi(input)
141
+ throw new TypeError('CLi.from expects an object or CLi instance')
150
142
  }
151
143
  }
package/src/CLiMessage.js CHANGED
@@ -1,9 +1,8 @@
1
- import { UiMessage } from "@nan0web/ui"
1
+ import { UiMessage } from '@nan0web/ui'
2
2
 
3
3
  /**
4
4
  * @class CLiMessage
5
5
  * @deprecated Use UiMessage that is the same
6
6
  * @extends UiMessage
7
7
  */
8
- export default class CLiMessage extends UiMessage {
9
- }
8
+ export default class CLiMessage extends UiMessage {}