@nan0web/ui 1.1.0 → 1.5.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.
Files changed (95) hide show
  1. package/README.md +48 -14
  2. package/package.json +25 -13
  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 +119 -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,18 +21,17 @@ 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
46
31
  * # @nan0web/ui
47
32
  *
33
+ * 🏴󠁧󠁢󠁥󠁮󠁧󠁿 [English](./README.md) | 🇺🇦 [Українською](./docs/uk/README.md)
34
+ *
48
35
  * <!-- %PACKAGE_STATUS% -->
49
36
  *
50
37
  * A lightweight, agnostic UI framework designed with the **nan0web philosophy**
@@ -65,35 +52,35 @@ function testRender() {
65
52
  *
66
53
  * ## Installation
67
54
  */
68
- it("How to install with npm?", () => {
55
+ it('How to install with npm?', () => {
69
56
  /**
70
57
  * ```bash
71
58
  * npm install @nan0web/ui
72
59
  * ```
73
60
  */
74
- assert.equal(pkg.name, "@nan0web/ui")
61
+ assert.equal(pkg.name, '@nan0web/ui')
75
62
  })
76
63
  /**
77
64
  * @docs
78
65
  */
79
- it("How to install with pnpm?", () => {
66
+ it('How to install with pnpm?', () => {
80
67
  /**
81
68
  * ```bash
82
69
  * pnpm add @nan0web/ui
83
70
  * ```
84
71
  */
85
- assert.equal(pkg.name, "@nan0web/ui")
72
+ assert.equal(pkg.name, '@nan0web/ui')
86
73
  })
87
74
  /**
88
75
  * @docs
89
76
  */
90
- it("How to install with yarn?", () => {
77
+ it('How to install with yarn?', () => {
91
78
  /**
92
79
  * ```bash
93
80
  * yarn add @nan0web/ui
94
81
  * ```
95
82
  */
96
- assert.equal(pkg.name, "@nan0web/ui")
83
+ assert.equal(pkg.name, '@nan0web/ui')
97
84
  })
98
85
 
99
86
  /**
@@ -110,16 +97,16 @@ function testRender() {
110
97
  * Messages are simple, serializable data containers. They help build
111
98
  * decoupled communication systems between UI components.
112
99
  */
113
- it("How to create input and output messages?", () => {
100
+ it('How to create input and output messages?', () => {
114
101
  //import { InputMessage, OutputMessage } from '@nan0web/ui'
115
102
 
116
103
  const input = UiMessage.from({ body: 'Hello User' })
117
104
  const output = OutputMessage.from({ content: ['Welcome to @nan0web/ui'] })
118
105
  console.info(input) // ← Message { body: "Hello User", head: {}, id: "....", type: "" }
119
106
  console.info(String(output)) // ← Welcome to @nan0web/ui
120
- assert.deepStrictEqual(console.output()[0][1].body, "Hello User")
107
+ assert.deepStrictEqual(console.output()[0][1].body, 'Hello User')
121
108
  assert.deepStrictEqual(console.output()[0][1].head, {})
122
- assert.deepStrictEqual(console.output()[0][1].type, "")
109
+ assert.deepStrictEqual(console.output()[0][1].type, '')
123
110
  assert.ok(console.output()[0][1].id)
124
111
  assert.ok(console.output()[1][1].endsWith('Welcome to @nan0web/ui'))
125
112
  })
@@ -140,27 +127,32 @@ function testRender() {
140
127
  * - `checkbox`
141
128
  * - `textarea`
142
129
  */
143
- it("How to define and validate a UiForm?", () => {
130
+ it('How to define and validate a UiForm?', () => {
144
131
  //import { UiForm } from '@nan0web/ui'
145
132
 
146
133
  const form = new UiForm({
147
- title: "Contact Form",
134
+ title: 'Contact Form',
148
135
  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 })
136
+ FormInput.from({ name: 'email', label: 'Email Address', type: 'email', required: true }),
137
+ FormInput.from({
138
+ name: 'message',
139
+ label: 'Your Message',
140
+ type: 'textarea',
141
+ required: true,
142
+ }),
151
143
  ],
152
144
  state: {
153
- email: "invalid-email",
154
- message: "Hello!"
155
- }
145
+ email: 'invalid-email',
146
+ message: 'Hello!',
147
+ },
156
148
  })
157
149
 
158
150
  const errors = form.validate()
159
151
  console.info(errors.size) // ← 1
160
- console.info(errors.get("email")) // ← Invalid email format
152
+ console.info(errors.get('email')) // ← Invalid email format
161
153
 
162
154
  assert.equal(console.output()[0][1], 1)
163
- assert.equal(console.output()[1][1], "Invalid email format")
155
+ assert.equal(console.output()[1][1], 'Invalid email format')
164
156
  })
165
157
 
166
158
  /**
@@ -172,13 +164,13 @@ function testRender() {
172
164
  * - `Welcome` – greets user by name
173
165
  * - `Process` – shows progress bar and time
174
166
  */
175
- it("How to render the Welcome component?", () => {
167
+ it('How to render the Welcome component?', () => {
176
168
  //import { Welcome } from '@nan0web/ui'
177
169
 
178
- const frame = Welcome({ user: { name: "Alice" } })
179
- const firstLine = frame[0].join("")
170
+ const frame = Welcome({ user: { name: 'Alice' } })
171
+ const firstLine = frame[0].join('')
180
172
  console.info(firstLine) // ← Welcome Alice!
181
- assert.equal(console.output()[0][1], "Welcome Alice!")
173
+ assert.equal(console.output()[0][1], 'Welcome Alice!')
182
174
  })
183
175
 
184
176
  /**
@@ -193,13 +185,13 @@ function testRender() {
193
185
  * - StdIn / StdOut – input/output streams
194
186
  * - Frame – output buffer with visual properties
195
187
  */
196
- it("How to render frame with View?", () => {
188
+ it('How to render frame with View?', () => {
197
189
  //import { View } from '@nan0web/ui'
198
190
 
199
191
  const view = new View()
200
- view.render(1)(["Hello, world"])
192
+ view.render(1)(['Hello, world'])
201
193
  console.info(String(view.frame)) // ← "\rHello, world"
202
- assert.ok(String(view.frame).includes("Hello, world"))
194
+ assert.ok(String(view.frame).includes('Hello, world'))
203
195
  })
204
196
 
205
197
  /**
@@ -215,36 +207,36 @@ function testRender() {
215
207
  * - `REPLACE` – erases and replaces full frame area
216
208
  * - `VISIBLE` – renders only visible part of frame
217
209
  */
218
- it("How to create a Frame with fixed size?", () => {
210
+ it('How to create a Frame with fixed size?', () => {
219
211
  //import { Frame } from '@nan0web/ui'
220
212
 
221
213
  const frame = new Frame({
222
- value: [["Frame content"]],
214
+ value: [['Frame content']],
223
215
  width: 20,
224
216
  height: 5,
225
217
  renderMethod: Frame.RenderMethod.APPEND,
226
218
  })
227
219
 
228
220
  const rendered = frame.render()
229
- console.info(rendered.includes("Frame content")) // ← true
230
- assert.ok(rendered.includes("Frame content"))
221
+ console.info(rendered.includes('Frame content')) // ← true
222
+ assert.ok(rendered.includes('Frame content'))
231
223
  })
232
- it("How to create a Frame with different render methods?", () => {
224
+ it('How to create a Frame with different render methods?', () => {
233
225
  //import { Frame } from '@nan0web/ui'
234
226
 
235
227
  const frame = new Frame({
236
- value: [["Frame content"]],
228
+ value: [['Frame content']],
237
229
  width: 20,
238
230
  height: 5,
239
231
  })
240
232
 
241
233
  frame.renderMethod = Frame.RenderMethod.REPLACE
242
234
  const renderedReplace = frame.render()
243
- assert.ok(renderedReplace.includes("Frame content"))
235
+ assert.ok(renderedReplace.includes('Frame content'))
244
236
 
245
237
  frame.renderMethod = Frame.RenderMethod.VISIBLE
246
238
  const renderedVisible = frame.render()
247
- assert.ok(renderedVisible.includes("Frame content"))
239
+ assert.ok(renderedVisible.includes('Frame content'))
248
240
  })
249
241
 
250
242
  /**
@@ -255,14 +247,14 @@ function testRender() {
255
247
  *
256
248
  * - `User` – user data
257
249
  */
258
- it("How to use a User model?", () => {
250
+ it('How to use a User model?', () => {
259
251
  //import { Model } from '@nan0web/ui'
260
252
 
261
- const user = new Model.User({ name: "Charlie", email: "charlie@example.com" })
253
+ const user = new Model.User({ name: 'Charlie', email: 'charlie@example.com' })
262
254
  console.info(user.name) // ← Charlie
263
255
  console.info(user.email) // ← charlie@example.com
264
- assert.equal(user.name, "Charlie")
265
- assert.equal(user.email, "charlie@example.com")
256
+ assert.equal(user.name, 'Charlie')
257
+ assert.equal(user.email, 'charlie@example.com')
266
258
  })
267
259
 
268
260
  /**
@@ -274,18 +266,47 @@ function testRender() {
274
266
  * All components, adapters, and models are designed to be testable
275
267
  * with minimal setup.
276
268
  */
277
- it("How to test UI components with assertions?", () => {
269
+ it('How to test UI components with assertions?', () => {
278
270
  //import { Welcome } from '@nan0web/ui'
279
271
 
280
- const output = Welcome({ user: { name: "Test" } })
272
+ const output = Welcome({ user: { name: 'Test' } })
281
273
  console.info(output) // ← Welcome Test!
282
274
  assert.deepStrictEqual(console.output()[0][1], [
283
- ["Welcome", " ", "Test", "!"],
284
- ["What can we do today great?"],
285
- [""],
275
+ ['Welcome', ' ', 'Test', '!'],
276
+ ['What can we do today great?'],
277
+ [''],
286
278
  ])
287
279
  })
288
280
 
281
+ /**
282
+ * @docs
283
+ * ### Master IDE (Component Sandbox)
284
+ *
285
+ * The Master IDE (OlmuiInspector) provides a unified environment for testing and documenting
286
+ * web components across platforms. It supports:
287
+ *
288
+ * - **NaN0 Spec** — a concise YAML-based shorthand for declaring component variations.
289
+ * - **OlmuiInspector** — unified UI for exploring component models and props.
290
+ * - **Live Preview** — real-time rendering of component states.
291
+ * - **i18n UI** — fully localized interface for global developers.
292
+ *
293
+ * It follows the **Olmui** core pattern: *One Logic — Many UI* (same manifest powers both CLI and Web).
294
+ *
295
+ * #### NaN0 Spec (YAML)
296
+ *
297
+ * Concise format for defining variations:
298
+ */
299
+ it('How to define a component variation using NaN0 Spec?', () => {
300
+ /**
301
+ * ```yaml
302
+ * - Button: Primary
303
+ * $variant: brand
304
+ * $outline: true
305
+ * ```
306
+ */
307
+ assert.ok(pkg.name === '@nan0web/ui')
308
+ })
309
+
289
310
  /**
290
311
  * @docs
291
312
  * ## Playground Demos
@@ -299,7 +320,7 @@ function testRender() {
299
320
  *
300
321
  * Run to explore live functionality:
301
322
  */
302
- it("How to run the playground?", async () => {
323
+ it('How to run the playground?', async () => {
303
324
  /**
304
325
  * ```bash
305
326
  * # Clone repository and run playground
@@ -309,10 +330,10 @@ function testRender() {
309
330
  * npm run play
310
331
  * ```
311
332
  */
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"))
333
+ assert.ok(String(pkg.scripts?.play).includes('node play'))
334
+ const response = await runSpawn('git', ['remote', 'get-url', 'origin'])
335
+ assert.ok(response.code === 0, 'git command fails (e.g., not in a git repo)')
336
+ assert.ok(response.text.trim().endsWith(':nan0web/ui.git'))
316
337
  })
317
338
 
318
339
  /**
@@ -330,41 +351,45 @@ function testRender() {
330
351
  * - [App](./src/App/)
331
352
  * - [Models](./src/Model/)
332
353
  *
354
+ * ## Project Architecture & Specs
355
+ *
356
+ * How the universal block spec is designed? - [check Universal Blocks Spec (`project.md`)](./project.md)
357
+ *
333
358
  * ## Contributing
334
359
  */
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"))
360
+ it('How to contribute? - [check here](./CONTRIBUTING.md)', async () => {
361
+ assert.equal(pkg.scripts?.precommit, 'npm test')
362
+ assert.equal(pkg.scripts?.prepush, 'npm test')
363
+ assert.equal(pkg.scripts?.prepare, 'husky')
364
+ const str = await fs.loadDocumentAs('.txt', 'CONTRIBUTING.md')
365
+ assert.ok(str.includes('# Contributing'))
342
366
  })
343
367
 
344
368
  /**
345
369
  * @docs
346
370
  * ## License
347
371
  */
348
- it("How to license ISC? - [check here](./LICENSE)", async () => {
372
+ it('How to license ISC? - [check here](./LICENSE)', async () => {
349
373
  /** @docs */
350
- const text = await fs.loadDocument("LICENSE")
351
- assert.ok(String(text).includes("ISC"))
374
+ const text = await fs.loadDocumentAs('.txt', 'LICENSE')
375
+ assert.ok(text.includes('ISC'))
352
376
  })
353
377
  }
354
378
 
355
- describe("README.md testing", testRender)
379
+ describe('README.md testing', testRender)
356
380
 
357
- describe("Rendering README.md", async () => {
358
- let text = ""
359
- const format = new Intl.NumberFormat("en-US").format
381
+ describe('Rendering README.md', async () => {
382
+ let text = ''
383
+ const format = new Intl.NumberFormat('en-US').format
360
384
  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)
385
+ const source = await fs.loadDocument('src/README.md.js')
386
+ text = String(parser.decode(source))
387
+ await fs.saveDocument('README.md', { content: text })
388
+ const dataset = DatasetParser.parse(text, pkg?.name ?? '@nan0web/ui')
389
+ await fs.saveDocument('.datasets/README.dataset.jsonl', dataset)
365
390
 
366
391
  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"))
392
+ const text = await fs.loadDocumentAs('.txt', 'README.md')
393
+ assert.ok(text.includes('## License'))
369
394
  })
370
395
  })
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 = {