@nan0web/ui 1.10.0 → 1.12.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 (101) hide show
  1. package/README.md +69 -3
  2. package/package.json +65 -29
  3. package/src/App/Command/DepsCommand.js +3 -4
  4. package/src/Frame/Props.js +12 -18
  5. package/src/InterfaceTemplate/InterfaceTemplate.js +9 -7
  6. package/src/Model/index.js +61 -6
  7. package/src/StdIn.js +2 -6
  8. package/src/cli.js +1 -0
  9. package/src/core/GeneratorRunner.js +67 -7
  10. package/src/core/InputAdapter.js +22 -5
  11. package/src/core/Intent.js +230 -18
  12. package/src/core/Message/Message.js +4 -7
  13. package/src/core/Message/OutputMessage.js +4 -9
  14. package/src/core/StreamEntry.js +20 -28
  15. package/src/core/index.js +4 -0
  16. package/src/domain/Content.js +198 -0
  17. package/src/domain/Document.js +25 -0
  18. package/src/domain/FooterModel.js +37 -19
  19. package/src/domain/HeaderModel.js +47 -21
  20. package/src/domain/HeroModel.js +24 -22
  21. package/src/domain/LayoutModel.js +43 -0
  22. package/src/domain/ModelAsApp.js +46 -0
  23. package/src/domain/SandboxModel.js +19 -16
  24. package/src/domain/app/GalleryCommand.js +53 -0
  25. package/src/domain/app/GalleryRenderIntent.js +77 -0
  26. package/src/domain/app/SnapshotAuditor.js +399 -0
  27. package/src/domain/app/SnapshotRunner.js +264 -0
  28. package/src/domain/app/UIApp.js +78 -0
  29. package/src/domain/components/BreadcrumbModel.js +10 -6
  30. package/src/domain/components/FeatureGridModel.js +62 -0
  31. package/src/domain/components/MarkdownModel.js +24 -0
  32. package/src/domain/components/ShellModel.js +243 -0
  33. package/src/domain/components/TableModel.js +10 -6
  34. package/src/domain/components/ToastModel.js +10 -6
  35. package/src/domain/components/index.js +3 -1
  36. package/src/domain/index.js +14 -4
  37. package/src/index.js +23 -2
  38. package/src/inspect.js +2 -0
  39. package/src/test/ScenarioAdapter.js +59 -0
  40. package/src/test/ScenarioTest.js +51 -0
  41. package/src/test/ScenarioTest.story.js +56 -0
  42. package/src/testing/CrashReporter.js +56 -0
  43. package/src/testing/GalleryGenerator.js +15 -71
  44. package/src/testing/LogicInspector.js +4 -4
  45. package/src/testing/SnapshotRunner.js +22 -0
  46. package/src/testing/SpecAdapter.js +114 -0
  47. package/src/testing/SpecRunner.js +121 -0
  48. package/src/testing/VisualAdapter.js +24 -19
  49. package/src/testing/index.js +5 -1
  50. package/src/testing/verifySnapshot.js +17 -0
  51. package/types/App/Command/DepsCommand.d.ts +0 -2
  52. package/types/Model/index.d.ts +56 -62
  53. package/types/StdIn.d.ts +3 -3
  54. package/types/cli.d.ts +1 -0
  55. package/types/core/GeneratorRunner.d.ts +14 -1
  56. package/types/core/InputAdapter.d.ts +50 -6
  57. package/types/core/Intent.d.ts +280 -32
  58. package/types/core/Message/Message.d.ts +2 -2
  59. package/types/core/Message/OutputMessage.d.ts +0 -2
  60. package/types/core/index.d.ts +4 -0
  61. package/types/domain/Content.d.ts +344 -0
  62. package/types/domain/Document.d.ts +40 -0
  63. package/types/domain/FooterModel.d.ts +22 -12
  64. package/types/domain/HeaderModel.d.ts +36 -13
  65. package/types/domain/HeroModel.d.ts +19 -17
  66. package/types/domain/LayoutModel.d.ts +34 -0
  67. package/types/domain/ModelAsApp.d.ts +23 -0
  68. package/types/domain/SandboxModel.d.ts +10 -0
  69. package/types/domain/app/GalleryCommand.d.ts +55 -0
  70. package/types/domain/app/GalleryRenderIntent.d.ts +31 -0
  71. package/types/domain/app/SnapshotAuditor.d.ts +99 -0
  72. package/types/domain/app/SnapshotRunner.d.ts +45 -0
  73. package/types/domain/app/UIApp.d.ts +60 -0
  74. package/types/domain/components/BreadcrumbModel.d.ts +6 -8
  75. package/types/domain/components/FeatureGridModel.d.ts +50 -0
  76. package/types/domain/components/MarkdownModel.d.ts +19 -0
  77. package/types/domain/components/ShellModel.d.ts +56 -0
  78. package/types/domain/components/TableModel.d.ts +4 -0
  79. package/types/domain/components/ToastModel.d.ts +4 -0
  80. package/types/domain/components/index.d.ts +3 -0
  81. package/types/domain/index.d.ts +10 -4
  82. package/types/index.d.ts +21 -1
  83. package/types/inspect.d.ts +2 -0
  84. package/types/test/ScenarioAdapter.d.ts +43 -0
  85. package/types/test/ScenarioTest.d.ts +24 -0
  86. package/types/test/ScenarioTest.story.d.ts +1 -0
  87. package/types/testing/CrashReporter.d.ts +13 -0
  88. package/types/testing/SnapshotRunner.d.ts +7 -0
  89. package/types/testing/SpecAdapter.d.ts +58 -0
  90. package/types/testing/SpecRunner.d.ts +41 -0
  91. package/types/testing/VisualAdapter.d.ts +0 -6
  92. package/types/testing/index.d.ts +5 -1
  93. package/types/testing/verifySnapshot.d.ts +14 -0
  94. package/src/testing/SnapshotInspector.js +0 -84
  95. package/types/App/Command/Options.d.ts +0 -43
  96. package/types/App/Command/index.d.ts +0 -8
  97. package/types/App/User/Command/Options.d.ts +0 -34
  98. package/types/core/Message/InputMessage.d.ts +0 -71
  99. package/types/domain/components/HeroModel.d.ts +0 -24
  100. package/types/domain/components/ShowcaseAppModel.d.ts +0 -32
  101. package/types/testing/SnapshotInspector.d.ts +0 -17
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @typedef {Object} SpecAdapterOptions
3
+ * @property {typeof import('node:assert/strict')} [assert] Custom assertion library (falls back to node:assert in Node runtime)
4
+ */
5
+ export class SpecAdapter {
6
+ /**
7
+ * @param {Array<object>} stream The remaining nan0 array without the first element.
8
+ * @param {SpecAdapterOptions} [options={}]
9
+ */
10
+ constructor(stream: Array<object>, options?: SpecAdapterOptions);
11
+ /** @type {Array<object>} */
12
+ stream: Array<object>;
13
+ /** @type {typeof import('node:assert/strict')} */
14
+ assert: typeof import("node:assert/strict");
15
+ /**
16
+ * @param {import('../core/Intent.js').AskIntent} intent
17
+ */
18
+ ask(intent: import("../core/Intent.js").AskIntent): Promise<{
19
+ value: any;
20
+ cancelled: boolean;
21
+ }>;
22
+ /**
23
+ * @param {import('../core/Intent.js').ShowIntent} intent
24
+ */
25
+ show(intent: import("../core/Intent.js").ShowIntent): Promise<void>;
26
+ /**
27
+ * @param {import('../core/Intent.js').LogIntent} intent
28
+ */
29
+ log(intent: import("../core/Intent.js").LogIntent): Promise<void>;
30
+ /**
31
+ * @param {import('../core/Intent.js').ProgressIntent} intent
32
+ */
33
+ progress(intent: import("../core/Intent.js").ProgressIntent): Promise<void>;
34
+ /**
35
+ * @param {import('../core/Intent.js').RenderIntent} intent
36
+ */
37
+ render(intent: import("../core/Intent.js").RenderIntent): Promise<void>;
38
+ /**
39
+ * @param {import('../core/Intent.js').AgentIntent} intent
40
+ */
41
+ agent(intent: import("../core/Intent.js").AgentIntent): Promise<{
42
+ success: boolean;
43
+ files: any;
44
+ message: any;
45
+ }>;
46
+ /**
47
+ * @param {import('../core/Intent.js').ResultIntent} intent
48
+ */
49
+ result(intent: import("../core/Intent.js").ResultIntent): Promise<void>;
50
+ #private;
51
+ }
52
+ export type SpecAdapterOptions = {
53
+ /**
54
+ * Custom assertion library (falls back to node:assert in Node runtime)
55
+ */
56
+ assert?: typeof assert | undefined;
57
+ };
58
+ import assert from 'node:assert/strict';
@@ -0,0 +1,41 @@
1
+ export class SpecRunner extends ModelAsApp {
2
+ static stream: {
3
+ help: string;
4
+ default: never[];
5
+ };
6
+ static registry: {
7
+ help: string;
8
+ default: {};
9
+ };
10
+ static UI: {
11
+ invalidStream: string;
12
+ invalidFirstStep: string;
13
+ missingAppName: string;
14
+ appNotFound: string;
15
+ invalidGenerator: string;
16
+ running: string;
17
+ unhandledSteps: string;
18
+ };
19
+ /**
20
+ * Run a Nan0Spec sequence programmatically (for unit tests).
21
+ *
22
+ * @param {Array<object>} stream The .nan0 intent stream array
23
+ * @param {Record<string, any>} registry A registry of Model Classes that can be mounted
24
+ * @param {typeof import('node:assert/strict')} [asserter] Custom assertion library
25
+ */
26
+ static execute(stream: Array<object>, registry: Record<string, any>, asserter?: typeof import("node:assert/strict")): Promise<any>;
27
+ /**
28
+ * @param {Partial<SpecRunner>} [data={}]
29
+ * @param {Partial<import('../index.js').ModelAsAppOptions> & { assert?: typeof import('node:assert/strict') }} [options={}]
30
+ */
31
+ constructor(data?: Partial<SpecRunner>, options?: Partial<import("../index.js").ModelAsAppOptions> & {
32
+ assert?: typeof import("node:assert/strict");
33
+ });
34
+ /** @type {Array<object>} The Nan0Spec stream */
35
+ stream: Array<object>;
36
+ /** @type {Record<string, any>} The registry of Model Classes */
37
+ registry: Record<string, any>;
38
+ #private;
39
+ }
40
+ export default SpecRunner;
41
+ import { ModelAsApp } from '../domain/ModelAsApp.js';
@@ -1,9 +1,3 @@
1
- /**
2
- * VisualAdapter (Base)
3
- *
4
- * Базовий клас для візуальної трансформації інтенцій OLMUI.
5
- * Використовувана у @nan0web/ui як фундамент для спеціалізованих рендерерів.
6
- */
7
1
  export class VisualAdapter {
8
2
  /**
9
3
  * Конвертує одну інтенцію у просте текстове представлення.
@@ -1,3 +1,7 @@
1
1
  export * from "./LogicInspector.js";
2
2
  export * from "./VisualAdapter.js";
3
- export * from "./SnapshotInspector.js";
3
+ export * from "../domain/app/SnapshotAuditor.js";
4
+ export * from "./verifySnapshot.js";
5
+ export * from "./CrashReporter.js";
6
+ export { SpecRunner } from "./SpecRunner.js";
7
+ export { SpecAdapter } from "./SpecAdapter.js";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Saves a logical JSONL snapshot sequence
3
+ * @param {Object} options
4
+ * @param {string} options.name Snapshot file name (e.g. 'uk/ExploreCatalog.jsonl')
5
+ * @param {Array<Object>} options.data Array of intents to serialize
6
+ * @param {typeof import('node:fs/promises')} [options.fs] Injected filesystem
7
+ * @param {typeof import('node:path')} [options.path] Injected path module
8
+ */
9
+ export function verifySnapshot({ name, data, fs, path }: {
10
+ name: string;
11
+ data: Array<any>;
12
+ fs?: typeof import("node:fs/promises") | undefined;
13
+ path?: import("path").PlatformPath | undefined;
14
+ }): Promise<void>;
@@ -1,84 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
-
4
- /**
5
- * SnapshotInspector
6
- *
7
- * Рев'ювер для автоматичної перевірки Snapshot-зліпків на наявність артефактів,
8
- * неперекладених ключів та структурних помилок.
9
- * Реалізує правила "Zero-Hallucination Snapshot Validation".
10
- */
11
- export class SnapshotInspector {
12
- /**
13
- * Перевіряє вміст одного снепшоту.
14
- * @param {string} content - Текстовий вміст .txt файлу галереї
15
- * @param {string} locale - Локаль (uk, en)
16
- * @param {string} [filename] - Ім'я файлу для перевірки на "глюки" (підкреслення)
17
- * @returns {object} { score, errors }
18
- */
19
- static inspect(content, locale = 'uk', filename = '') {
20
- const errors = []
21
- const lines = content.split('\n')
22
-
23
- // 0. Перевірка імені файлу (на прохання архітектора)
24
- if (filename) {
25
- if (/__|--/.test(filename)) {
26
- errors.push(`Filename "${filename}" has multiple consecutive separators (glitch detected).`)
27
- }
28
- if (filename.length < 3) {
29
- errors.push(`Filename "${filename}" is too short.`)
30
- }
31
- }
32
-
33
- lines.forEach((line, index) => {
34
- const lineNum = index + 1
35
- const trimmed = line.trim()
36
-
37
- // 1. Неперекладені i18n ключі (крапки в словах)
38
- // Виключаємо імена компонентів, атрибути RENDER-тегів, та числа з крапкою (версії, координати)
39
- const isAttribute = trimmed.includes('="')
40
- const isDotNumber = /^-?\d+\.\d+$/.test(trimmed)
41
-
42
- if (/\w+\.\w+/.test(line) && !line.includes('ui-') && !line.includes('http') && !isAttribute && !isDotNumber) {
43
- errors.push(`Line ${lineNum}: Possible untranslated key found: "${trimmed}"`)
44
- }
45
-
46
- // 2. Технічні артефакти
47
- if (line.includes('[object Object]')) {
48
- errors.push(`Line ${lineNum}: Critical artifact "[object Object]" found.`)
49
- }
50
- if (line.includes('undefined')) {
51
- errors.push(`Line ${lineNum}: Critical artifact "undefined" found.`)
52
- }
53
- if (line.includes('NaN')) {
54
- errors.push(`Line ${lineNum}: Critical artifact "NaN" found.`)
55
- }
56
-
57
- // 3. Англійські слова в українській локалі (базові)
58
- if (locale === 'uk') {
59
- const enWords = ['Back', 'Select', 'Cancel', 'Submit', 'Confirm', 'Delete', 'Information', 'Success', 'Warning', 'Error']
60
- enWords.forEach(word => {
61
- const regex = new RegExp(`\\b${word}\\b`, 'i')
62
- // Перевіряємо тільки якщо це не частина тегу <ui-...> або атрибут
63
- if (regex.test(line)) {
64
- const isTag = line.includes(`<ui-${word.toLowerCase()}`) || line.includes(`[RENDER] <ui-`)
65
- const isAsk = line.includes(`[ASK] ${word}`)
66
- if (!isTag && !isAsk && !isAttribute) {
67
- errors.push(`Line ${lineNum}: English word "${word}" found in "uk" locale.`)
68
- }
69
- }
70
- })
71
- }
72
-
73
- // 4. Помилки роутингу
74
- if (line.includes('🚨 Path not found')) {
75
- errors.push(`Line ${lineNum}: Routing error "Path not found".`)
76
- }
77
- })
78
-
79
- return {
80
- score: errors.length === 0 ? 100 : Math.max(0, 100 - errors.length * 10),
81
- errors
82
- }
83
- }
84
- }
@@ -1,43 +0,0 @@
1
- export default CommandOptions
2
- /**
3
- * Represents command options with default values.
4
- * Provides utilities for handling command line options.
5
- */
6
- declare class CommandOptions {
7
- /**
8
- * Default option values.
9
- * @type {object}
10
- * @property {boolean} help - Whether help is requested
11
- * @property {string} cwd - Current working directory
12
- */
13
- static DEFAULTS: object
14
- /**
15
- * Creates a CommandOptions instance from the given props.
16
- * @param {CommandOptions|object} props - The properties to create from
17
- * @returns {CommandOptions} A CommandOptions instance
18
- */
19
- static from(props: CommandOptions | object): CommandOptions
20
- /**
21
- * Creates a new CommandOptions instance.
22
- * @param {object} props - The properties for command options
23
- * @param {boolean} [props.help=false] - Whether help is requested
24
- * @param {string} [props.cwd=""] - Current working directory
25
- */
26
- constructor(props?: { help?: boolean | undefined; cwd?: string | undefined })
27
- /** @type {boolean} Whether help is requested */
28
- help: boolean
29
- /** @type {string} Current working directory */
30
- cwd: string
31
- /** @type {Record<string, any>} */
32
- get DEFAULTS(): Record<string, any>
33
- /**
34
- * Checks if all options have their default values.
35
- * @returns {boolean} True if all options are at their default values, false otherwise
36
- */
37
- get empty(): boolean
38
- /**
39
- * Converts the options to a string representation.
40
- * @returns {string} String representation of the options or "<no options>" if none set
41
- */
42
- toString(): string
43
- }
@@ -1,8 +0,0 @@
1
- declare namespace _default {
2
- export { CommandMessage as Message }
3
- export { CommandOptions as Options }
4
- }
5
- export default _default
6
- import { CommandMessage } from '@nan0web/co'
7
- import CommandOptions from './Options.js'
8
- export { CommandMessage, CommandOptions }
@@ -1,34 +0,0 @@
1
- export default UserAppCommandOptions
2
- /**
3
- * Extends CommandOptions to include user-specific options.
4
- */
5
- declare class UserAppCommandOptions {
6
- /**
7
- * Default option values including inherited ones.
8
- * @type {object}
9
- * @property {boolean} help - Whether help is requested
10
- * @property {string} cwd - Current working directory
11
- * @property {string} user - User name
12
- */
13
- static DEFAULTS: object
14
- /**
15
- * Creates a UserAppCommandOptions instance from the given props.
16
- * @param {UserAppCommandOptions|object} props - The properties to create from
17
- * @returns {UserAppCommandOptions} A UserAppCommandOptions instance
18
- */
19
- static from(props: UserAppCommandOptions | object): UserAppCommandOptions
20
- /**
21
- * Creates a new UserAppCommandOptions instance.
22
- * @param {object} props - Options properties
23
- * @param {boolean} [props.help=false] - Whether help is requested
24
- * @param {string} [props.cwd=""] - Current working directory
25
- * @param {string} [props.user=""] - User name
26
- */
27
- constructor(props?: {
28
- help?: boolean | undefined
29
- cwd?: string | undefined
30
- user?: string | undefined
31
- })
32
- /** @type {string} User name */
33
- user: string
34
- }
@@ -1,71 +0,0 @@
1
- /** @typedef {Partial<Message> | null} InputMessageValue */
2
- /**
3
- * Represents a message input with value, options, and metadata.
4
- */
5
- export default class InputMessage {
6
- static ESCAPE: string
7
- /**
8
- * Creates an InputMessage instance from the given value.
9
- * @param {InputMessage|object|string} value - The value to create from
10
- * @returns {InputMessage} An InputMessage instance
11
- */
12
- static from(value: InputMessage | object | string): InputMessage
13
- /**
14
- * Creates a new InputMessage instance.
15
- * @param {object} props - Input message properties
16
- * @param {InputMessageValue} [props.value=null] - Input value
17
- * @param {string[]|string} [props.options=[]] - Available options
18
- * @param {boolean} [props.waiting=false] - Waiting state flag
19
- * @param {boolean} [props.escaped=false] - Sets value to escape when true
20
- */
21
- constructor(props?: {
22
- value?: InputMessageValue | undefined
23
- options?: string | string[] | undefined
24
- waiting?: boolean | undefined
25
- escaped?: boolean | undefined
26
- })
27
- /** @type {Message} Input value */
28
- value: Message
29
- /** @type {string[]} Available options for this input */
30
- options: string[]
31
- /** @type {boolean} Whether this input is waiting for response */
32
- waiting: boolean
33
- /**
34
- * Checks if the input value is empty.
35
- * @returns {boolean} True if value is empty or null, false otherwise
36
- */
37
- get empty(): boolean
38
- /**
39
- * Gets the timestamp when input was created.
40
- * @returns {number} Creation timestamp
41
- */
42
- get time(): number
43
- /**
44
- * Returns the escape value.
45
- * @returns {string}
46
- */
47
- get ESCAPE(): string
48
- /**
49
- * Checks if the input is an escape sequence.
50
- * @returns {boolean} True if input value is escape sequence, false otherwise
51
- */
52
- get escaped(): boolean
53
- /**
54
- * Validates if the input has a non-empty value.
55
- * @returns {boolean} True if input is valid, false otherwise
56
- */
57
- get isValid(): boolean
58
- /**
59
- * Converts the input to a plain object representation.
60
- * @returns {object} Object with all properties including timestamp
61
- */
62
- toObject(): object
63
- /**
64
- * Converts the input to a string representation including timestamp.
65
- * @returns {string} String representation with timestamp and value
66
- */
67
- toString(): string
68
- #private
69
- }
70
- export type InputMessageValue = Partial<Message> | null
71
- import { Message } from '@nan0web/co'
@@ -1,24 +0,0 @@
1
- /**
2
- * HeroModel — OLMUI Model-as-Schema
3
- * Main landing page banner with a big heading, description, and primary CTA.
4
- */
5
- export class HeroModel extends Model {
6
- static $id: string;
7
- static title: {
8
- help: string;
9
- placeholder: string;
10
- default: string;
11
- required: boolean;
12
- };
13
- static description: {
14
- help: string;
15
- placeholder: string;
16
- default: string;
17
- };
18
- static actions: {
19
- help: string;
20
- type: string;
21
- default: never[];
22
- };
23
- }
24
- import { Model } from '@nan0web/core';
@@ -1,32 +0,0 @@
1
- /**
2
- * ShowcaseAppModel — OLMUI Model-as-Schema
3
- * A container model representing the entire UI library showcase.
4
- * @property {string} title - App title
5
- * @property {any[]} sections - Collection of UI sections
6
- */
7
- export class ShowcaseAppModel extends Model {
8
- static $id: string;
9
- static title: {
10
- help: string;
11
- default: string;
12
- };
13
- static sections: {
14
- help: string;
15
- type: string;
16
- default: never[];
17
- };
18
- /**
19
- * OLMUI Generator — drives the showcase rendering.
20
- */
21
- run(): AsyncGenerator<{
22
- type: string;
23
- message: any;
24
- component: string;
25
- }, {
26
- type: string;
27
- data: {
28
- success: boolean;
29
- };
30
- }, unknown>;
31
- }
32
- import { Model } from '@nan0web/core';
@@ -1,17 +0,0 @@
1
- /**
2
- * SnapshotInspector
3
- *
4
- * Рев'ювер для автоматичної перевірки Snapshot-зліпків на наявність артефактів,
5
- * неперекладених ключів та структурних помилок.
6
- * Реалізує правила "Zero-Hallucination Snapshot Validation".
7
- */
8
- export class SnapshotInspector {
9
- /**
10
- * Перевіряє вміст одного снепшоту.
11
- * @param {string} content - Текстовий вміст .txt файлу галереї
12
- * @param {string} locale - Локаль (uk, en)
13
- * @param {string} [filename] - Ім'я файлу для перевірки на "глюки" (підкреслення)
14
- * @returns {object} { score, errors }
15
- */
16
- static inspect(content: string, locale?: string, filename?: string): object;
17
- }