@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.
Files changed (95) hide show
  1. package/README.md +19 -14
  2. package/package.json +6 -4
  3. package/src/App/Command/DepsCommand.js +5 -9
  4. package/src/App/Core/CoreApp.js +18 -17
  5. package/src/App/Core/UI.js +11 -15
  6. package/src/App/Core/Widget.js +6 -10
  7. package/src/App/Core/index.js +3 -3
  8. package/src/App/Scenario.js +4 -4
  9. package/src/App/User/Command/Message.js +1 -1
  10. package/src/App/User/Command/index.js +1 -1
  11. package/src/App/User/UserApp.js +28 -21
  12. package/src/App/User/UserUI.js +2 -2
  13. package/src/App/User/index.js +2 -2
  14. package/src/App/index.js +5 -10
  15. package/src/Component/Process/Input.js +10 -17
  16. package/src/Component/Process/Process.js +3 -5
  17. package/src/Component/Process/index.js +2 -2
  18. package/src/Component/SortableList/SortableList.js +100 -0
  19. package/src/Component/SortableList/index.js +3 -0
  20. package/src/Component/Welcome/Input.js +2 -4
  21. package/src/Component/Welcome/Welcome.js +5 -9
  22. package/src/Component/Welcome/index.js +2 -2
  23. package/src/Component/index.js +5 -3
  24. package/src/Frame/Frame.js +163 -146
  25. package/src/Frame/Props.js +20 -20
  26. package/src/Locale.js +17 -18
  27. package/src/Model/User/User.js +3 -6
  28. package/src/Model/index.js +1 -1
  29. package/src/README.md.js +84 -94
  30. package/src/StdIn.js +8 -12
  31. package/src/StdOut.js +23 -27
  32. package/src/View/RenderOptions.js +1 -1
  33. package/src/View/View.js +40 -36
  34. package/src/core/Error/CancelError.js +2 -2
  35. package/src/core/Error/index.js +3 -5
  36. package/src/core/Flow.js +347 -0
  37. package/src/core/Form/Form.js +35 -33
  38. package/src/core/Form/Input.js +21 -6
  39. package/src/core/Form/Message.js +3 -6
  40. package/src/core/Form/index.js +4 -8
  41. package/src/core/InputAdapter.js +4 -6
  42. package/src/core/Message/Message.js +9 -12
  43. package/src/core/Message/OutputMessage.js +19 -17
  44. package/src/core/Message/index.js +2 -2
  45. package/src/core/OutputAdapter.js +12 -10
  46. package/src/core/Stream.js +1 -1
  47. package/src/core/StreamEntry.js +2 -2
  48. package/src/core/UiAdapter.js +31 -30
  49. package/src/core/index.js +33 -10
  50. package/src/functions.js +8 -15
  51. package/src/index.js +21 -32
  52. package/types/App/Command/DepsCommand.d.ts +1 -1
  53. package/types/App/Command/Options.d.ts +37 -40
  54. package/types/App/Command/index.d.ts +6 -6
  55. package/types/App/Core/CoreApp.d.ts +2 -2
  56. package/types/App/Core/UI.d.ts +4 -4
  57. package/types/App/Core/Widget.d.ts +4 -4
  58. package/types/App/Core/index.d.ts +3 -3
  59. package/types/App/Scenario.d.ts +1 -1
  60. package/types/App/User/Command/Message.d.ts +1 -1
  61. package/types/App/User/Command/Options.d.ts +29 -29
  62. package/types/App/User/Command/index.d.ts +1 -1
  63. package/types/App/User/UserApp.d.ts +5 -5
  64. package/types/App/User/index.d.ts +2 -2
  65. package/types/App/index.d.ts +4 -4
  66. package/types/Component/Process/Process.d.ts +2 -2
  67. package/types/Component/Process/index.d.ts +2 -2
  68. package/types/Component/SortableList/SortableList.d.ts +58 -0
  69. package/types/Component/SortableList/index.d.ts +2 -0
  70. package/types/Component/Welcome/Input.d.ts +1 -1
  71. package/types/Component/Welcome/Welcome.d.ts +1 -1
  72. package/types/Component/Welcome/index.d.ts +2 -2
  73. package/types/Component/index.d.ts +5 -3
  74. package/types/Frame/Frame.d.ts +1 -1
  75. package/types/Frame/Props.d.ts +1 -1
  76. package/types/Model/index.d.ts +1 -1
  77. package/types/StdIn.d.ts +2 -2
  78. package/types/StdOut.d.ts +1 -1
  79. package/types/View/View.d.ts +7 -7
  80. package/types/core/Error/index.d.ts +1 -1
  81. package/types/core/Flow.d.ts +320 -0
  82. package/types/core/Form/Form.d.ts +2 -2
  83. package/types/core/Form/Input.d.ts +11 -0
  84. package/types/core/Form/Message.d.ts +1 -1
  85. package/types/core/Form/index.d.ts +3 -3
  86. package/types/core/InputAdapter.d.ts +2 -2
  87. package/types/core/Intent.d.ts +65 -68
  88. package/types/core/Message/InputMessage.d.ts +65 -65
  89. package/types/core/Message/Message.d.ts +1 -1
  90. package/types/core/Message/OutputMessage.d.ts +1 -1
  91. package/types/core/Message/index.d.ts +2 -2
  92. package/types/core/Stream.d.ts +1 -1
  93. package/types/core/UiAdapter.d.ts +5 -5
  94. package/types/core/index.d.ts +4 -3
  95. package/types/index.d.ts +10 -10
package/src/Locale.js CHANGED
@@ -1,4 +1,4 @@
1
- import { typeOf, notEmpty } from "@nan0web/types"
1
+ import { typeOf, notEmpty } from '@nan0web/types'
2
2
 
3
3
  /**
4
4
  * Handles locale-specific formatting for different data types.
@@ -42,14 +42,14 @@ export default class Locale {
42
42
  */
43
43
  constructor(props = {}) {
44
44
  const {
45
- lang = "",
46
- collate = "",
47
- ctype = "",
48
- messages = "",
49
- monetary = "",
50
- numeric = "",
51
- time = "",
52
- all = "uk_UA.UTF-8",
45
+ lang = '',
46
+ collate = '',
47
+ ctype = '',
48
+ messages = '',
49
+ monetary = '',
50
+ numeric = '',
51
+ time = '',
52
+ all = 'uk_UA.UTF-8',
53
53
  } = props
54
54
  this.lang = lang
55
55
  this.collate = collate
@@ -70,9 +70,9 @@ export default class Locale {
70
70
  format(type, options) {
71
71
  if (Number === type || typeOf(Number)(type)) {
72
72
  /**
73
- * new (locales?: LocalesArgument, options?: NumberFormatOptions): NumberFormat;
74
- * (locales?: LocalesArgument, options?: NumberFormatOptions): NumberFormat;
75
- * supportedLocalesOf(locales: LocalesArgument, options?: NumberFormatOptions): string[];
73
+ * new (locales?: LocalesArgument, options?: NumberFormatOptions): NumberFormat;
74
+ * (locales?: LocalesArgument, options?: NumberFormatOptions): NumberFormat;
75
+ * supportedLocalesOf(locales: LocalesArgument, options?: NumberFormatOptions): string[];
76
76
  */
77
77
  /**
78
78
  * localeMatcher?: "lookup" | "best fit" | undefined;
@@ -85,18 +85,18 @@ export default class Locale {
85
85
  * maximumFractionDigits?: number | undefined;
86
86
  * minimumSignificantDigits?: number | undefined;
87
87
  * maximumSignificantDigits?: number | undefined;
88
- */
88
+ */
89
89
  const locales = [this.numeric, this.all, this.lang].filter(notEmpty)
90
90
  return (value) => {
91
91
  return new Intl.NumberFormat(locales, options).format(value)
92
92
  }
93
93
  }
94
- if ("string" === typeof type) {
94
+ if ('string' === typeof type) {
95
95
  const locales = [this.monetary, this.numeric, this.all, this.lang].filter(notEmpty)
96
96
  return (value) => {
97
97
  return new Intl.NumberFormat(locales, {
98
- style: "currency",
99
- currency: type === "currency" ? options.currency : type,
98
+ style: 'currency',
99
+ currency: type === 'currency' ? options.currency : type,
100
100
  ...options,
101
101
  }).format(value)
102
102
  }
@@ -110,10 +110,9 @@ export default class Locale {
110
110
  */
111
111
  static from(input) {
112
112
  if (input instanceof Locale) return input
113
- if ("string" === typeof input) {
113
+ if ('string' === typeof input) {
114
114
  return new Locale({ all: input })
115
115
  }
116
116
  return new Locale(input)
117
117
  }
118
118
  }
119
-
@@ -15,10 +15,7 @@ class User {
15
15
  * @param {string} [props.email=""] - User email
16
16
  */
17
17
  constructor(props = {}) {
18
- const {
19
- name = "",
20
- email = "",
21
- } = props
18
+ const { name = '', email = '' } = props
22
19
  this.name = String(name)
23
20
  this.email = String(email)
24
21
  }
@@ -36,7 +33,7 @@ class User {
36
33
  * @returns {string} User name and email (if exists)
37
34
  */
38
35
  toString() {
39
- return [this.name, this.email ? `<${this.email}>` : ""].filter(Boolean).join(" ")
36
+ return [this.name, this.email ? `<${this.email}>` : ''].filter(Boolean).join(' ')
40
37
  }
41
38
 
42
39
  /**
@@ -46,7 +43,7 @@ class User {
46
43
  */
47
44
  static from(props) {
48
45
  if (props instanceof User) return props
49
- if ("string" === typeof props) {
46
+ if ('string' === typeof props) {
50
47
  return new User({ name: props })
51
48
  }
52
49
  return new User(props)
@@ -1,4 +1,4 @@
1
- import User from "./User/User.js"
1
+ import User from './User/User.js'
2
2
 
3
3
  export { User }
4
4
 
package/src/README.md.js CHANGED
@@ -1,29 +1,17 @@
1
- import { describe, it, before, beforeEach } from "node:test"
2
- import assert from "node:assert/strict"
3
- import FS from "@nan0web/db-fs"
4
- import { NoConsole } from "@nan0web/log"
5
- import {
6
- DatasetParser,
7
- DocsParser,
8
- runSpawn,
9
- } from "@nan0web/test"
10
- import {
11
- Frame,
12
- Model,
13
- OutputMessage,
14
- View,
15
- FormInput,
16
- UiMessage,
17
- UiForm,
18
- } from "./index.js"
19
- import { Welcome } from "./Component/index.js"
1
+ import { describe, it, before, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import FS from '@nan0web/db-fs'
4
+ import { NoConsole } from '@nan0web/log'
5
+ import { DatasetParser, DocsParser, runSpawn } from '@nan0web/test'
6
+ import { Frame, Model, OutputMessage, View, FormInput, UiMessage, UiForm } from './index.js'
7
+ import { Welcome } from './Component/index.js'
20
8
 
21
9
  const fs = new FS()
22
10
  let pkg
23
11
 
24
12
  // Load package.json once before tests
25
13
  before(async () => {
26
- const doc = await fs.loadDocument("package.json", {})
14
+ const doc = await fs.loadDocument('package.json', {})
27
15
  pkg = doc || {}
28
16
  })
29
17
 
@@ -33,13 +21,10 @@ beforeEach((info) => {
33
21
  console = new NoConsole()
34
22
  })
35
23
 
36
- /**
37
- * Core test suite that also serves as the source for README generation.
38
- *
39
- * The block comments inside each `it` block are extracted to build
40
- * the final `README.md`. Keeping the comments here ensures the
41
- * documentation stays close to the code.
42
- */
24
+ // Core test suite that also serves as the source for README generation.
25
+ // The block comments inside each `it` block are extracted to build
26
+ // the final `README.md`. Keeping the comments here ensures the
27
+ // documentation stays close to the code.
43
28
  function testRender() {
44
29
  /**
45
30
  * @docs
@@ -65,35 +50,35 @@ function testRender() {
65
50
  *
66
51
  * ## Installation
67
52
  */
68
- it("How to install with npm?", () => {
53
+ it('How to install with npm?', () => {
69
54
  /**
70
55
  * ```bash
71
56
  * npm install @nan0web/ui
72
57
  * ```
73
58
  */
74
- assert.equal(pkg.name, "@nan0web/ui")
59
+ assert.equal(pkg.name, '@nan0web/ui')
75
60
  })
76
61
  /**
77
62
  * @docs
78
63
  */
79
- it("How to install with pnpm?", () => {
64
+ it('How to install with pnpm?', () => {
80
65
  /**
81
66
  * ```bash
82
67
  * pnpm add @nan0web/ui
83
68
  * ```
84
69
  */
85
- assert.equal(pkg.name, "@nan0web/ui")
70
+ assert.equal(pkg.name, '@nan0web/ui')
86
71
  })
87
72
  /**
88
73
  * @docs
89
74
  */
90
- it("How to install with yarn?", () => {
75
+ it('How to install with yarn?', () => {
91
76
  /**
92
77
  * ```bash
93
78
  * yarn add @nan0web/ui
94
79
  * ```
95
80
  */
96
- assert.equal(pkg.name, "@nan0web/ui")
81
+ assert.equal(pkg.name, '@nan0web/ui')
97
82
  })
98
83
 
99
84
  /**
@@ -110,16 +95,16 @@ function testRender() {
110
95
  * Messages are simple, serializable data containers. They help build
111
96
  * decoupled communication systems between UI components.
112
97
  */
113
- it("How to create input and output messages?", () => {
98
+ it('How to create input and output messages?', () => {
114
99
  //import { InputMessage, OutputMessage } from '@nan0web/ui'
115
100
 
116
101
  const input = UiMessage.from({ body: 'Hello User' })
117
102
  const output = OutputMessage.from({ content: ['Welcome to @nan0web/ui'] })
118
103
  console.info(input) // ← Message { body: "Hello User", head: {}, id: "....", type: "" }
119
104
  console.info(String(output)) // ← Welcome to @nan0web/ui
120
- assert.deepStrictEqual(console.output()[0][1].body, "Hello User")
105
+ assert.deepStrictEqual(console.output()[0][1].body, 'Hello User')
121
106
  assert.deepStrictEqual(console.output()[0][1].head, {})
122
- assert.deepStrictEqual(console.output()[0][1].type, "")
107
+ assert.deepStrictEqual(console.output()[0][1].type, '')
123
108
  assert.ok(console.output()[0][1].id)
124
109
  assert.ok(console.output()[1][1].endsWith('Welcome to @nan0web/ui'))
125
110
  })
@@ -140,27 +125,32 @@ function testRender() {
140
125
  * - `checkbox`
141
126
  * - `textarea`
142
127
  */
143
- it("How to define and validate a UiForm?", () => {
128
+ it('How to define and validate a UiForm?', () => {
144
129
  //import { UiForm } from '@nan0web/ui'
145
130
 
146
131
  const form = new UiForm({
147
- title: "Contact Form",
132
+ title: 'Contact Form',
148
133
  fields: [
149
- FormInput.from({ name: "email", label: "Email Address", type: "email", required: true }),
150
- FormInput.from({ name: "message", label: "Your Message", type: "textarea", required: true })
134
+ FormInput.from({ name: 'email', label: 'Email Address', type: 'email', required: true }),
135
+ FormInput.from({
136
+ name: 'message',
137
+ label: 'Your Message',
138
+ type: 'textarea',
139
+ required: true,
140
+ }),
151
141
  ],
152
142
  state: {
153
- email: "invalid-email",
154
- message: "Hello!"
155
- }
143
+ email: 'invalid-email',
144
+ message: 'Hello!',
145
+ },
156
146
  })
157
147
 
158
148
  const errors = form.validate()
159
149
  console.info(errors.size) // ← 1
160
- console.info(errors.get("email")) // ← Invalid email format
150
+ console.info(errors.get('email')) // ← Invalid email format
161
151
 
162
152
  assert.equal(console.output()[0][1], 1)
163
- assert.equal(console.output()[1][1], "Invalid email format")
153
+ assert.equal(console.output()[1][1], 'Invalid email format')
164
154
  })
165
155
 
166
156
  /**
@@ -172,13 +162,13 @@ function testRender() {
172
162
  * - `Welcome` – greets user by name
173
163
  * - `Process` – shows progress bar and time
174
164
  */
175
- it("How to render the Welcome component?", () => {
165
+ it('How to render the Welcome component?', () => {
176
166
  //import { Welcome } from '@nan0web/ui'
177
167
 
178
- const frame = Welcome({ user: { name: "Alice" } })
179
- const firstLine = frame[0].join("")
168
+ const frame = Welcome({ user: { name: 'Alice' } })
169
+ const firstLine = frame[0].join('')
180
170
  console.info(firstLine) // ← Welcome Alice!
181
- assert.equal(console.output()[0][1], "Welcome Alice!")
171
+ assert.equal(console.output()[0][1], 'Welcome Alice!')
182
172
  })
183
173
 
184
174
  /**
@@ -193,13 +183,13 @@ function testRender() {
193
183
  * - StdIn / StdOut – input/output streams
194
184
  * - Frame – output buffer with visual properties
195
185
  */
196
- it("How to render frame with View?", () => {
186
+ it('How to render frame with View?', () => {
197
187
  //import { View } from '@nan0web/ui'
198
188
 
199
189
  const view = new View()
200
- view.render(1)(["Hello, world"])
190
+ view.render(1)(['Hello, world'])
201
191
  console.info(String(view.frame)) // ← "\rHello, world"
202
- assert.ok(String(view.frame).includes("Hello, world"))
192
+ assert.ok(String(view.frame).includes('Hello, world'))
203
193
  })
204
194
 
205
195
  /**
@@ -215,36 +205,36 @@ function testRender() {
215
205
  * - `REPLACE` – erases and replaces full frame area
216
206
  * - `VISIBLE` – renders only visible part of frame
217
207
  */
218
- it("How to create a Frame with fixed size?", () => {
208
+ it('How to create a Frame with fixed size?', () => {
219
209
  //import { Frame } from '@nan0web/ui'
220
210
 
221
211
  const frame = new Frame({
222
- value: [["Frame content"]],
212
+ value: [['Frame content']],
223
213
  width: 20,
224
214
  height: 5,
225
215
  renderMethod: Frame.RenderMethod.APPEND,
226
216
  })
227
217
 
228
218
  const rendered = frame.render()
229
- console.info(rendered.includes("Frame content")) // ← true
230
- assert.ok(rendered.includes("Frame content"))
219
+ console.info(rendered.includes('Frame content')) // ← true
220
+ assert.ok(rendered.includes('Frame content'))
231
221
  })
232
- it("How to create a Frame with different render methods?", () => {
222
+ it('How to create a Frame with different render methods?', () => {
233
223
  //import { Frame } from '@nan0web/ui'
234
224
 
235
225
  const frame = new Frame({
236
- value: [["Frame content"]],
226
+ value: [['Frame content']],
237
227
  width: 20,
238
228
  height: 5,
239
229
  })
240
230
 
241
231
  frame.renderMethod = Frame.RenderMethod.REPLACE
242
232
  const renderedReplace = frame.render()
243
- assert.ok(renderedReplace.includes("Frame content"))
233
+ assert.ok(renderedReplace.includes('Frame content'))
244
234
 
245
235
  frame.renderMethod = Frame.RenderMethod.VISIBLE
246
236
  const renderedVisible = frame.render()
247
- assert.ok(renderedVisible.includes("Frame content"))
237
+ assert.ok(renderedVisible.includes('Frame content'))
248
238
  })
249
239
 
250
240
  /**
@@ -255,14 +245,14 @@ function testRender() {
255
245
  *
256
246
  * - `User` – user data
257
247
  */
258
- it("How to use a User model?", () => {
248
+ it('How to use a User model?', () => {
259
249
  //import { Model } from '@nan0web/ui'
260
250
 
261
- const user = new Model.User({ name: "Charlie", email: "charlie@example.com" })
251
+ const user = new Model.User({ name: 'Charlie', email: 'charlie@example.com' })
262
252
  console.info(user.name) // ← Charlie
263
253
  console.info(user.email) // ← charlie@example.com
264
- assert.equal(user.name, "Charlie")
265
- assert.equal(user.email, "charlie@example.com")
254
+ assert.equal(user.name, 'Charlie')
255
+ assert.equal(user.email, 'charlie@example.com')
266
256
  })
267
257
 
268
258
  /**
@@ -274,15 +264,15 @@ function testRender() {
274
264
  * All components, adapters, and models are designed to be testable
275
265
  * with minimal setup.
276
266
  */
277
- it("How to test UI components with assertions?", () => {
267
+ it('How to test UI components with assertions?', () => {
278
268
  //import { Welcome } from '@nan0web/ui'
279
269
 
280
- const output = Welcome({ user: { name: "Test" } })
270
+ const output = Welcome({ user: { name: 'Test' } })
281
271
  console.info(output) // ← Welcome Test!
282
272
  assert.deepStrictEqual(console.output()[0][1], [
283
- ["Welcome", " ", "Test", "!"],
284
- ["What can we do today great?"],
285
- [""],
273
+ ['Welcome', ' ', 'Test', '!'],
274
+ ['What can we do today great?'],
275
+ [''],
286
276
  ])
287
277
  })
288
278
 
@@ -299,7 +289,7 @@ function testRender() {
299
289
  *
300
290
  * Run to explore live functionality:
301
291
  */
302
- it("How to run the playground?", async () => {
292
+ it('How to run the playground?', async () => {
303
293
  /**
304
294
  * ```bash
305
295
  * # Clone repository and run playground
@@ -309,10 +299,10 @@ function testRender() {
309
299
  * npm run play
310
300
  * ```
311
301
  */
312
- assert.ok(String(pkg.scripts?.play).includes("node play"))
313
- const response = await runSpawn("git", ["remote", "get-url", "origin"])
314
- assert.ok(response.code === 0, "git command fails (e.g., not in a git repo)")
315
- assert.ok(response.text.trim().endsWith(":nan0web/ui.git"))
302
+ assert.ok(String(pkg.scripts?.play).includes('node play'))
303
+ const response = await runSpawn('git', ['remote', 'get-url', 'origin'])
304
+ assert.ok(response.code === 0, 'git command fails (e.g., not in a git repo)')
305
+ assert.ok(response.text.trim().endsWith(':nan0web/ui.git'))
316
306
  })
317
307
 
318
308
  /**
@@ -332,39 +322,39 @@ function testRender() {
332
322
  *
333
323
  * ## Contributing
334
324
  */
335
- it("How to contribute? - [check here](./CONTRIBUTING.md)", async () => {
336
- assert.equal(pkg.scripts?.precommit, "npm test")
337
- assert.equal(pkg.scripts?.prepush, "npm test")
338
- assert.equal(pkg.scripts?.prepare, "husky")
339
- const text = await fs.loadDocument("CONTRIBUTING.md")
340
- const str = String(text)
341
- assert.ok(str.includes("# Contributing"))
325
+ it('How to contribute? - [check here](./CONTRIBUTING.md)', async () => {
326
+ assert.equal(pkg.scripts?.precommit, 'npm test')
327
+ assert.equal(pkg.scripts?.prepush, 'npm test')
328
+ assert.equal(pkg.scripts?.prepare, 'husky')
329
+ const str = await fs.loadDocumentAs('.txt', 'CONTRIBUTING.md')
330
+ assert.ok(str.includes('# Contributing'))
342
331
  })
343
332
 
344
333
  /**
345
334
  * @docs
346
335
  * ## License
347
336
  */
348
- it("How to license ISC? - [check here](./LICENSE)", async () => {
337
+ it('How to license ISC? - [check here](./LICENSE)', async () => {
349
338
  /** @docs */
350
- const text = await fs.loadDocument("LICENSE")
351
- assert.ok(String(text).includes("ISC"))
339
+ const text = await fs.loadDocumentAs('.txt', 'LICENSE')
340
+ assert.ok(text.includes('ISC'))
352
341
  })
353
342
  }
354
343
 
355
- describe("README.md testing", testRender)
344
+ describe('README.md testing', testRender)
356
345
 
357
- describe("Rendering README.md", async () => {
358
- let text = ""
359
- const format = new Intl.NumberFormat("en-US").format
346
+ describe('Rendering README.md', async () => {
347
+ let text = ''
348
+ const format = new Intl.NumberFormat('en-US').format
360
349
  const parser = new DocsParser()
361
- text = String(parser.decode(testRender))
362
- await fs.saveDocument("README.md", text)
363
- const dataset = DatasetParser.parse(text, pkg.name)
364
- await fs.saveDocument(".datasets/README.dataset.jsonl", dataset)
350
+ const source = await fs.loadDocument('src/README.md.js')
351
+ text = String(parser.decode(source))
352
+ await fs.saveDocument('README.md', { content: text })
353
+ const dataset = DatasetParser.parse(text, pkg?.name ?? '@nan0web/ui')
354
+ await fs.saveDocument('.datasets/README.dataset.jsonl', dataset)
365
355
 
366
356
  it(`document is rendered in README.md [${format(Buffer.byteLength(text))}b]`, async () => {
367
- const text = await fs.loadDocument("README.md")
368
- assert.ok(text.includes("## License"))
357
+ const text = await fs.loadDocumentAs('.txt', 'README.md')
358
+ assert.ok(text.includes('## License'))
369
359
  })
370
360
  })
package/src/StdIn.js CHANGED
@@ -1,8 +1,8 @@
1
- import EventProcessor from "@nan0web/event/oop"
2
- import { typeOf } from "@nan0web/types"
3
- import { UiMessage } from "./core/index.js"
1
+ import EventProcessor from '@nan0web/event/oop'
2
+ import { typeOf } from '@nan0web/types'
3
+ import { UiMessage } from './core/index.js'
4
4
 
5
- class Processor extends EventProcessor { }
5
+ class Processor extends EventProcessor {}
6
6
 
7
7
  /**
8
8
  * Handles standard input stream with message buffering.
@@ -12,7 +12,7 @@ export default class StdIn extends EventProcessor {
12
12
  static READ_INTERVAL = 99
13
13
 
14
14
  /** @type {string[]} Messages to ignore */
15
- static IGNORE_MESSAGES = ["", "undefined"]
15
+ static IGNORE_MESSAGES = ['', 'undefined']
16
16
 
17
17
  /** @type {UiMessage[]} Input message buffer */
18
18
  stream = []
@@ -28,13 +28,10 @@ export default class StdIn extends EventProcessor {
28
28
  */
29
29
  constructor(props = {}) {
30
30
  super()
31
- const {
32
- processor = new Processor(),
33
- stream = [],
34
- } = props
31
+ const { processor = new Processor(), stream = [] } = props
35
32
  this.processor = processor
36
33
  this.stream = stream
37
- this.processor?.on("data", (data) => {
34
+ this.processor?.on('data', (data) => {
38
35
  this.write(data)
39
36
  })
40
37
  }
@@ -62,7 +59,7 @@ export default class StdIn extends EventProcessor {
62
59
  */
63
60
  async read() {
64
61
  while (this.ended) {
65
- await new Promise(resolve => setTimeout(resolve, StdIn.READ_INTERVAL))
62
+ await new Promise((resolve) => setTimeout(resolve, StdIn.READ_INTERVAL))
66
63
  }
67
64
  return this.stream.shift() ?? new UiMessage()
68
65
  }
@@ -105,4 +102,3 @@ export default class StdIn extends EventProcessor {
105
102
  return new this(input)
106
103
  }
107
104
  }
108
-
package/src/StdOut.js CHANGED
@@ -1,40 +1,40 @@
1
- import { typeOf } from "@nan0web/types"
2
- import EventProcessor from "@nan0web/event/oop"
1
+ import { typeOf } from '@nan0web/types'
2
+ import EventProcessor from '@nan0web/event/oop'
3
3
 
4
4
  /**
5
5
  * Handles standard output stream with formatting capabilities.
6
6
  */
7
7
  class StdOut extends EventProcessor {
8
8
  /** @type {string} End of line character */
9
- static EOL = "\n"
9
+ static EOL = '\n'
10
10
 
11
11
  /** @type {string} Beginning of line character */
12
- static BOL = "\r"
12
+ static BOL = '\r'
13
13
 
14
14
  /** @type {string} Reset formatting escape code */
15
- static RESET = "\x1b[0m"
15
+ static RESET = '\x1b[0m'
16
16
 
17
17
  /** @type {string} Clear screen escape code */
18
- static CLEAR = "\x1b[2J\x1b[H"
18
+ static CLEAR = '\x1b[2J\x1b[H'
19
19
 
20
20
  /** @type {object} Color escape codes */
21
21
  static COLORS = {
22
- red: "\x1b[31m",
23
- green: "\x1b[32m",
24
- yellow: "\x1b[33m",
25
- blue: "\x1b[34m",
26
- magenta: "\x1b[35m",
27
- cyan: "\x1b[36m",
28
- white: "\x1b[37m",
29
- gray: "\x1b[90m",
30
- black: "\x1b[30m",
22
+ red: '\x1b[31m',
23
+ green: '\x1b[32m',
24
+ yellow: '\x1b[33m',
25
+ blue: '\x1b[34m',
26
+ magenta: '\x1b[35m',
27
+ cyan: '\x1b[36m',
28
+ white: '\x1b[37m',
29
+ gray: '\x1b[90m',
30
+ black: '\x1b[30m',
31
31
  }
32
32
 
33
33
  /** @type {Record<string, string>} Style escape codes */
34
34
  static STYLES = {
35
- dim: "\x1b[2m",
36
- bold: "\x1b[1m",
37
- underline: "\x1b[4m",
35
+ dim: '\x1b[2m',
36
+ bold: '\x1b[1m',
37
+ underline: '\x1b[4m',
38
38
  }
39
39
 
40
40
  /**
@@ -59,11 +59,7 @@ class StdOut extends EventProcessor {
59
59
  */
60
60
  constructor(props = {}) {
61
61
  super()
62
- const {
63
- processor,
64
- stream = [],
65
- windowSize = [144, 33],
66
- } = props
62
+ const { processor, stream = [], windowSize = [144, 33] } = props
67
63
  this.processor = processor
68
64
  this.stream = stream
69
65
  this.windowSize = windowSize
@@ -75,16 +71,16 @@ class StdOut extends EventProcessor {
75
71
  * @param {any} output - Output to write
76
72
  * @param {Function} onError - Error handler callback
77
73
  */
78
- write(output, onError = v => 1) {
79
- /**
74
+ write(output, onError = (v) => 1) {
75
+ /**
80
76
  * @todo manage the
81
77
  */
82
78
  if (typeOf(Array)(output)) {
83
- output = output.join("\n")
79
+ output = output.join('\n')
84
80
  }
85
81
  this.stream.push(output)
86
82
  this.processor?.write(output, onError)
87
- this.emit("data", output)
83
+ this.emit('data', output)
88
84
  }
89
85
 
90
86
  /**
@@ -1,4 +1,4 @@
1
- import Frame from "../Frame/Frame.js"
1
+ import Frame from '../Frame/Frame.js'
2
2
 
3
3
  class RenderOptions {
4
4
  static DEFAULTS = {