jsgui3-server 0.0.150 → 0.0.152

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 (86) hide show
  1. package/.github/instructions/copilot.instructions.md +1 -0
  2. package/AGENTS.md +2 -0
  3. package/README.md +89 -13
  4. package/admin-ui/v1/controls/admin_shell.js +702 -669
  5. package/admin-ui/v1/server.js +14 -1
  6. package/docs/api-reference.md +504 -306
  7. package/docs/books/creating-a-new-admin-ui/README.md +20 -20
  8. package/docs/books/website-design/01-introduction.md +73 -0
  9. package/docs/books/website-design/02-current-state.md +195 -0
  10. package/docs/books/website-design/03-base-class.md +181 -0
  11. package/docs/books/website-design/04-webpage.md +307 -0
  12. package/docs/books/website-design/05-website.md +456 -0
  13. package/docs/books/website-design/06-pages-storage.md +170 -0
  14. package/docs/books/website-design/07-api-layer.md +285 -0
  15. package/docs/books/website-design/08-server-integration.md +271 -0
  16. package/docs/books/website-design/09-cross-agent-review.md +190 -0
  17. package/docs/books/website-design/10-open-questions.md +196 -0
  18. package/docs/books/website-design/11-converged-recommendation.md +205 -0
  19. package/docs/books/website-design/12-content-model.md +395 -0
  20. package/docs/books/website-design/13-webpage-module-spec.md +404 -0
  21. package/docs/books/website-design/14-website-module-spec.md +541 -0
  22. package/docs/books/website-design/15-multi-repo-plan.md +275 -0
  23. package/docs/books/website-design/16-minimal-first.md +203 -0
  24. package/docs/books/website-design/17-implementation-report-codex.md +81 -0
  25. package/docs/books/website-design/README.md +43 -0
  26. package/docs/comprehensive-documentation.md +220 -220
  27. package/docs/configuration-reference.md +281 -204
  28. package/docs/middleware-guide.md +236 -0
  29. package/docs/proposals/jsgui3-website-and-webpage-design-jsgui3-server-support.md +257 -0
  30. package/docs/proposals/jsgui3-website-and-webpage-design-review.md +73 -0
  31. package/docs/proposals/jsgui3-website-and-webpage-design.md +732 -0
  32. package/docs/swagger.md +316 -0
  33. package/docs/system-architecture.md +24 -18
  34. package/examples/controls/1) window/server.js +6 -1
  35. package/examples/controls/21) mvvm and declarative api/check.js +94 -0
  36. package/examples/controls/21) mvvm and declarative api/check_output.txt +25 -0
  37. package/examples/controls/21) mvvm and declarative api/check_output_2.txt +27 -0
  38. package/examples/controls/21) mvvm and declarative api/client.js +241 -0
  39. declarative api/e2e-screenshot-1-name-change.png +0 -0
  40. declarative api/e2e-screenshot-2-toggled.png +0 -0
  41. declarative api/e2e-screenshot-3-final.png +0 -0
  42. declarative api/e2e-screenshot-final.png +0 -0
  43. package/examples/controls/21) mvvm and declarative api/e2e-test.js +175 -0
  44. package/examples/controls/21) mvvm and declarative api/out.html +1 -0
  45. package/examples/controls/21) mvvm and declarative api/page_out.html +1 -0
  46. package/examples/controls/21) mvvm and declarative api/server.js +18 -0
  47. package/examples/data-views/01) query-endpoint/server.js +61 -0
  48. package/labs/website-design/001-base-class-overhead/check.js +162 -0
  49. package/labs/website-design/002-pages-storage/check.js +244 -0
  50. package/labs/website-design/002-pages-storage/results.txt +0 -0
  51. package/labs/website-design/003-type-detection/check.js +193 -0
  52. package/labs/website-design/003-type-detection/results.txt +0 -0
  53. package/labs/website-design/004-two-stage-validation/check.js +314 -0
  54. package/labs/website-design/004-two-stage-validation/results.txt +0 -0
  55. package/labs/website-design/005-normalize-input/check.js +303 -0
  56. package/labs/website-design/006-serve-website-spike/check.js +290 -0
  57. package/labs/website-design/README.md +34 -0
  58. package/labs/website-design/manifest.json +68 -0
  59. package/labs/website-design/run-all.js +60 -0
  60. package/middleware/compression.js +217 -0
  61. package/middleware/index.js +15 -0
  62. package/middleware/json-body.js +126 -0
  63. package/module.js +3 -0
  64. package/openapi.js +474 -0
  65. package/package.json +11 -8
  66. package/publishers/Publishers.js +6 -5
  67. package/publishers/http-function-publisher.js +135 -126
  68. package/publishers/http-webpage-publisher.js +89 -11
  69. package/publishers/query-publisher.js +116 -0
  70. package/publishers/swagger-publisher.js +203 -0
  71. package/publishers/swagger-ui.js +578 -0
  72. package/resources/adapters/array-adapter.js +143 -0
  73. package/resources/query-resource.js +131 -0
  74. package/serve-factory.js +756 -18
  75. package/server.js +502 -123
  76. package/tests/README.md +23 -1
  77. package/tests/admin-ui-jsgui-controls.test.js +16 -1
  78. package/tests/helpers/playwright-e2e-harness.js +326 -0
  79. package/tests/openapi.test.js +319 -0
  80. package/tests/playwright-smoke.test.js +134 -0
  81. package/tests/publish-enhancements.test.js +673 -0
  82. package/tests/query-publisher.test.js +430 -0
  83. package/tests/quick-json-body-test.js +169 -0
  84. package/tests/serve.test.js +425 -122
  85. package/tests/swagger-publisher.test.js +1076 -0
  86. package/tests/test-runner.js +1 -0
@@ -0,0 +1,316 @@
1
+ # Swagger / OpenAPI Documentation
2
+
3
+ jsgui3-server includes **built-in, zero-dependency** Swagger / OpenAPI 3.0.3 support. Every API you define — whether through `Server.serve()` or `server.publish()` — is automatically documented and browsable via an interactive Swagger UI.
4
+
5
+ ## Quick Start
6
+
7
+ ```js
8
+ const Server = require('jsgui3-server/server');
9
+
10
+ Server.serve({
11
+ port: 8080,
12
+ api: {
13
+ 'users/list': {
14
+ handler: listUsers,
15
+ method: 'POST',
16
+ summary: 'List all users',
17
+ tags: ['Users']
18
+ }
19
+ }
20
+ });
21
+ ```
22
+
23
+ Open your browser:
24
+
25
+ | URL | Purpose |
26
+ |-----|---------|
27
+ | `http://localhost:8080/api/docs` | Interactive Swagger UI |
28
+ | `http://localhost:8080/api/openapi.json` | Raw OpenAPI 3.0 spec (JSON) |
29
+
30
+ ---
31
+
32
+ ## Configuration
33
+
34
+ The `swagger` option controls whether the routes are registered:
35
+
36
+ ```js
37
+ Server.serve({
38
+ swagger: true, // Always enable (default in dev)
39
+ swagger: false, // Always disable (default in production)
40
+ // swagger omitted → auto (enabled when NODE_ENV !== 'production')
41
+ });
42
+ ```
43
+
44
+ You can also pass an object for fine-grained control:
45
+
46
+ ```js
47
+ Server.serve({
48
+ swagger: {
49
+ title: 'My Service API',
50
+ version: '2.0.0',
51
+ description: 'Custom description for the spec info block'
52
+ }
53
+ });
54
+ ```
55
+
56
+ ### Environment-Based Defaults
57
+
58
+ | `NODE_ENV` | `swagger` omitted | `swagger: true` | `swagger: false` |
59
+ |--------------|-------------------|-----------------|------------------|
60
+ | development | ✅ enabled | ✅ enabled | ❌ disabled |
61
+ | production | ❌ disabled | ✅ enabled | ❌ disabled |
62
+ | *(unset)* | ✅ enabled | ✅ enabled | ❌ disabled |
63
+
64
+ ---
65
+
66
+ ## Defining API Metadata
67
+
68
+ ### Declarative API (recommended)
69
+
70
+ Pass metadata directly in the `api` option of `Server.serve()`:
71
+
72
+ ```js
73
+ Server.serve({
74
+ port: 8080,
75
+ api: {
76
+ 'products/search': {
77
+ handler: searchProducts,
78
+ method: 'POST',
79
+ summary: 'Search products',
80
+ description: 'Full-text search across the product catalog.',
81
+ tags: ['Products', 'Search'],
82
+ params: {
83
+ query: { type: 'string', description: 'Search query', required: true },
84
+ page: { type: 'integer', description: 'Page number', default: 1 },
85
+ page_size: { type: 'integer', description: 'Results per page', default: 25 },
86
+ sort: { type: 'string', description: 'Sort field', enum: ['name', 'price', 'date'] }
87
+ },
88
+ returns: {
89
+ rows: { type: 'array', items: { type: 'object' } },
90
+ total_count: { type: 'integer', description: 'Total matching results' },
91
+ page: { type: 'integer' }
92
+ }
93
+ }
94
+ }
95
+ });
96
+ ```
97
+
98
+ ### Imperative API
99
+
100
+ Use `server.publish()` with a `meta` object:
101
+
102
+ ```js
103
+ const server = new Server({ website: false });
104
+
105
+ server.publish('users/create', createUser, {
106
+ method: 'POST',
107
+ summary: 'Create a new user',
108
+ description: 'Creates a user account and returns the user object.',
109
+ tags: ['Users'],
110
+ params: {
111
+ name: { type: 'string', required: true, description: 'Full name' },
112
+ email: { type: 'string', required: true, description: 'Email address' }
113
+ },
114
+ returns: {
115
+ id: { type: 'integer', description: 'New user ID' },
116
+ name: { type: 'string' },
117
+ email: { type: 'string' }
118
+ }
119
+ });
120
+
121
+ // Register swagger routes after all publish() calls:
122
+ server._register_swagger_routes({ title: 'User Service' });
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Metadata Reference
128
+
129
+ All metadata fields are **optional**. Endpoints without metadata still produce a valid (minimal) Swagger entry.
130
+
131
+ ### Endpoint Metadata Fields
132
+
133
+ | Field | Type | Default | Purpose |
134
+ |----------------------|----------|-----------------|---------|
135
+ | `method` | string | `'POST'` | HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) |
136
+ | `summary` | string | — | One-line summary shown in Swagger UI operation list |
137
+ | `description` | string | — | Multi-line Markdown description for expanded view |
138
+ | `tags` | string[] | auto-detected | Grouping tags (auto-detected from route if omitted) |
139
+ | `params` | Object | — | Request body schema (see schema format below) |
140
+ | `returns` | Object | — | Response body schema (see schema format below) |
141
+ | `deprecated` | boolean | `false` | Strike-through in Swagger UI |
142
+ | `operationId` | string | auto-generated | Unique operation identifier |
143
+ | `response_description`| string | `'Successful response'` | Custom 200 response description |
144
+ | `schema` | Object | — | Alternative to `params` (from Function_Publisher) |
145
+
146
+ ### Schema Format
147
+
148
+ The `params` and `returns` objects use a simple `{key: definition}` format:
149
+
150
+ ```js
151
+ {
152
+ field_name: {
153
+ type: 'string', // 'string' | 'integer' | 'number' | 'boolean' | 'array' | 'object'
154
+ description: '...', // Human-readable description
155
+ default: 'value', // Default value
156
+ required: true, // Whether the field is required
157
+ enum: ['a', 'b'], // Allowed values
158
+ items: { type: '...' } // For type: 'array' — describes each item
159
+ }
160
+ }
161
+ ```
162
+
163
+ This simple format is automatically converted to OpenAPI Schema Objects by the spec generator.
164
+
165
+ You can also pass raw OpenAPI schemas if you need more control:
166
+
167
+ ```js
168
+ {
169
+ type: 'object',
170
+ properties: {
171
+ name: { type: 'string' },
172
+ age: { type: 'integer' }
173
+ },
174
+ required: ['name']
175
+ }
176
+ ```
177
+
178
+ ### Tag Auto-Detection
179
+
180
+ When an endpoint has no explicit `tags`, a tag is automatically derived from the route path:
181
+
182
+ | Route | Auto-Tag |
183
+ |-------|----------|
184
+ | `/api/users/list` | `users` |
185
+ | `/api/data/products` | `data` |
186
+ | `/api/admin/v1/status` | `admin` |
187
+ | `/health` | `health` |
188
+
189
+ ---
190
+
191
+ ## Architecture
192
+
193
+ ```
194
+ Server.serve({ api: {...} })
195
+
196
+ ├── serve-factory.js ─── normalises endpoints
197
+ │ │ preserves summary, tags, params, returns
198
+ │ ▼
199
+ ├── server.publish(name, fn, meta)
200
+ │ │
201
+ │ ├── Function_Publisher ─── stores api_meta
202
+ │ └── _api_registry[] ─── indexed for OpenAPI
203
+
204
+ └── _register_swagger_routes()
205
+
206
+ └── Swagger_Publisher (extends HTTP_Publisher)
207
+
208
+ ├── /api/openapi.json ─── openapi.js generates spec
209
+ │ walks _api_registry + function_publishers
210
+ │ converts params/returns → OpenAPI schemas
211
+
212
+ └── /api/docs ─── swagger-ui.js generates HTML
213
+ loads Swagger UI from CDN
214
+ dark theme matching jsgui3
215
+ ```
216
+
217
+ ### Source Files
218
+
219
+ | File | Purpose |
220
+ |------|---------|
221
+ | `publishers/swagger-publisher.js` | `Swagger_Publisher` class (extends `HTTP_Publisher`) |
222
+ | `openapi.js` | OpenAPI 3.0.3 spec generator (zero dependencies) |
223
+ | `publishers/swagger-ui.js` | HTML page generator (CDN-based Swagger UI) |
224
+ | `publishers/http-function-publisher.js` | Stores `api_meta` on publisher instances |
225
+ | `publishers/Publishers.js` | Registry — includes `'swagger'` entry |
226
+ | `server.js` | `publish()` + `_register_swagger_routes()` |
227
+ | `serve-factory.js` | Metadata flow + auto-registration |
228
+ | `tests/openapi.test.js` | 14 tests across 5 suites |
229
+
230
+ ---
231
+
232
+ ## Customisation
233
+
234
+ ### Title and Version
235
+
236
+ ```js
237
+ Server.serve({
238
+ swagger: { title: 'My API', version: '2.0.0' }
239
+ });
240
+ ```
241
+
242
+ ### Manual Registration
243
+
244
+ For servers created with `new Server(...)` directly:
245
+
246
+ ```js
247
+ const server = new Server({ website: false });
248
+ // ... server.publish() calls ...
249
+ server._register_swagger_routes({
250
+ title: 'My API',
251
+ version: '3.0.0',
252
+ description: 'API for my service'
253
+ });
254
+ ```
255
+
256
+ ### Standalone Publisher
257
+
258
+ You can also create a `Swagger_Publisher` independently and attach it
259
+ to any server with access to the router:
260
+
261
+ ```js
262
+ const Swagger_Publisher = require('jsgui3-server/publishers/swagger-publisher');
263
+
264
+ const swagger = new Swagger_Publisher({
265
+ server: my_server,
266
+ title: 'My API',
267
+ version: '3.0.0'
268
+ });
269
+
270
+ my_server.server_router.set_route('/api/openapi.json', swagger, swagger.handle_http.bind(swagger));
271
+ my_server.server_router.set_route('/api/docs', swagger, swagger.handle_http.bind(swagger));
272
+ ```
273
+
274
+ The publisher is also available in the `Publishers` registry:
275
+
276
+ ```js
277
+ const Publishers = require('jsgui3-server/publishers/Publishers');
278
+ const Swagger_Publisher = Publishers.swagger;
279
+ ```
280
+
281
+ ### Disabling in Production
282
+
283
+ Swagger is automatically disabled when `NODE_ENV=production`. To force it on:
284
+
285
+ ```js
286
+ Server.serve({ swagger: true });
287
+ ```
288
+
289
+ ---
290
+
291
+ ## How It Works Internally
292
+
293
+ 1. **Endpoint registration** — `server.publish()` creates a `Function_Publisher` and adds an entry to `server._api_registry` with the full metadata.
294
+
295
+ 2. **Metadata normalisation** — `serve-factory.js` preserves `summary`, `tags`, `params`, `returns`, and `schema` from the declarative API definition and passes them through to `publish()`.
296
+
297
+ 3. **Spec generation** — When `/api/openapi.json` is requested, `openapi.js` walks the `_api_registry` and `function_publishers` arrays, converts the simple schema format to OpenAPI Schema Objects, and assembles a complete OpenAPI 3.0.3 document.
298
+
299
+ 4. **Swagger UI** — When `/api/docs` is requested, a pre-generated HTML page is served that loads Swagger UI from the unpkg CDN and points it at `/api/openapi.json`.
300
+
301
+ ---
302
+
303
+ ## Testing
304
+
305
+ Run the test suite:
306
+
307
+ ```bash
308
+ node --test tests/openapi.test.js
309
+ ```
310
+
311
+ This runs 14 tests across 5 suites:
312
+ - **simple_schema_to_openapi** — schema conversion edge cases
313
+ - **generate_openapi_spec** — spec structure, minimal metadata, route filtering
314
+ - **collect_api_entries** — deduplication across data sources
315
+ - **generate_swagger_html** — HTML output and CDN links
316
+ - **Swagger routes integration** — end-to-end HTTP tests with a real server
@@ -32,29 +32,29 @@ JSGUI3 Server is a Node.js-based web framework that serves modern JavaScript GUI
32
32
 
33
33
  **Purpose:** Handles conversion of various content types to HTTP responses.
34
34
 
35
- **Key Publishers:**
36
- - `HTTP_Webpage_Publisher`: Serves bundled JSGUI3 controls as complete web pages
37
- - `HTTP_Website_Publisher`: Manages multi-page websites
38
- - `HTTP_Function_Publisher`: Exposes JavaScript functions as REST API endpoints
39
- - `HTTP_Observable_Publisher`: Streams observable-backed SSE
40
- - `HTTP_SSE_Publisher`: General-purpose SSE fan-out publisher
41
- - `HTTP_CSS_Publisher`: Serves CSS stylesheets
42
- - `HTTP_JS_Publisher`: Serves JavaScript bundles
43
- - `HTTP_Image_Publisher`: Handles image file serving
35
+ **Key Publishers:**
36
+ - `HTTP_Webpage_Publisher`: Serves bundled JSGUI3 controls as complete web pages
37
+ - `HTTP_Website_Publisher`: Manages multi-page websites
38
+ - `HTTP_Function_Publisher`: Exposes JavaScript functions as REST API endpoints
39
+ - `HTTP_Observable_Publisher`: Streams observable-backed SSE
40
+ - `HTTP_SSE_Publisher`: General-purpose SSE fan-out publisher
41
+ - `HTTP_CSS_Publisher`: Serves CSS stylesheets
42
+ - `HTTP_JS_Publisher`: Serves JavaScript bundles
43
+ - `HTTP_Image_Publisher`: Handles image file serving
44
44
 
45
45
  ### 3. Resource Management Layer
46
46
  **Directory:** `resources/`
47
47
 
48
48
  **Purpose:** Provides abstractions for accessing different types of data and functionality.
49
49
 
50
- **Key Resources:**
51
- - `Server_Resource_Pool`: Manages collections of resources with lifecycle management
52
- - `Process_Resource`: Local process resource (`direct` default, optional `pm2`)
53
- - `Remote_Process_Resource`: HTTP-controlled remote process resource
54
- - `Website_Resource`: Wraps website objects for server integration
55
- - `File_System_Resource`: Provides file system access
56
- - `Data_Resource`: Handles data storage and retrieval
57
- - `Local_Server_Info_Resource`: Provides server environment information
50
+ **Key Resources:**
51
+ - `Server_Resource_Pool`: Manages collections of resources with lifecycle management
52
+ - `Process_Resource`: Local process resource (`direct` default, optional `pm2`)
53
+ - `Remote_Process_Resource`: HTTP-controlled remote process resource
54
+ - `Website_Resource`: Wraps website objects for server integration
55
+ - `File_System_Resource`: Provides file system access
56
+ - `Data_Resource`: Handles data storage and retrieval
57
+ - `Local_Server_Info_Resource`: Provides server environment information
58
58
 
59
59
  ### 4. Processing Layer
60
60
  **Directory:** `resources/processors/`
@@ -105,6 +105,8 @@ Client Request
105
105
 
106
106
  HTTP Server (Node.js http/https)
107
107
 
108
+ Middleware Pipeline (server.use) ← gzip/deflate/brotli, CORS, logging, etc.
109
+
108
110
  Server Router
109
111
 
110
112
  Resource Pool
@@ -118,6 +120,10 @@ Content Processing/Bundling
118
120
  HTTP Response
119
121
  ```
120
122
 
123
+ Middleware functions registered via `server.use(fn)` execute in order before
124
+ the router. If no middleware is registered, the router is called directly
125
+ with zero overhead. See [Middleware Guide](middleware-guide.md) for details.
126
+
121
127
  ### Component Serving Flow
122
128
 
123
129
  ```
@@ -276,4 +282,4 @@ Add new processing pipelines for assets and data.
276
282
 
277
283
  ---
278
284
 
279
- This architecture document provides the foundation for understanding how JSGUI3 Server components work together. For detailed implementation of specific components, refer to their individual documentation files.
285
+ This architecture document provides the foundation for understanding how JSGUI3 Server components work together. For detailed implementation of specific components, refer to their individual documentation files.
@@ -105,9 +105,14 @@ if (require.main === module) {
105
105
  throw err;
106
106
  } else {
107
107
  // Should have build it by now...
108
-
108
+
109
109
  console.log('server started');
110
+ server.print_endpoints({
111
+ prefix: 'active endpoint'
112
+ });
110
113
  }
114
+ }, {
115
+ on_port_conflict: 'auto-loopback'
111
116
  });
112
117
  })
113
118
 
@@ -0,0 +1,94 @@
1
+ 'use strict';
2
+
3
+ const jsgui = require('./client');
4
+ const { UserProfileEditor } = jsgui.controls;
5
+
6
+ let pass = 0, fail = 0;
7
+ function check(label, ok) {
8
+ if (ok) { console.log(` ✅ ${label}`); pass++; }
9
+ else { console.log(` ❌ ${label}`); fail++; }
10
+ }
11
+
12
+ console.log('\n═══ MVVM & Declarative API Check ═══\n');
13
+
14
+ // ── 1. Construction & Model Initialisation ──────────────────────────
15
+ const editor = new UserProfileEditor({
16
+ first_name: 'John',
17
+ last_name: 'Smith',
18
+ is_active: true
19
+ });
20
+
21
+ check('Control instantiated', !!editor);
22
+ check('Has data.model layer', !!editor.data && !!editor.data.model);
23
+ check('Has view.data.model layer', !!editor.view && !!editor.view.data && !!editor.view.data.model);
24
+
25
+ // ── 2. Raw Model Values ─────────────────────────────────────────────
26
+ check('first_name stored correctly', editor.data.model.get('first_name').value === 'John');
27
+ check('last_name stored correctly', editor.data.model.get('last_name').value === 'Smith');
28
+ check('is_active stored correctly', editor.data.model.get('is_active').value === true);
29
+
30
+ // ── 3. Computed Properties ──────────────────────────────────────────
31
+ const fullName = editor.data.model.get('full_name').value;
32
+ check('Computed full_name = "John Smith"', fullName === 'John Smith');
33
+
34
+ const statusText = editor.data.model.get('status_text').value;
35
+ check('Computed status_text = "Active Account"', statusText === 'Active Account');
36
+
37
+ // ── 4. Server-Side HTML Rendering ───────────────────────────────────
38
+ const html = editor.all_html_render();
39
+ check('HTML renders without throwing', typeof html === 'string' && html.length > 0);
40
+ check('HTML has .profile-card wrapper', html.includes('profile-card'));
41
+ check('HTML has active-state class', html.includes('active-state'));
42
+ check('HTML has profile-header section', html.includes('profile-header'));
43
+ check('HTML has profile-body section', html.includes('profile-body'));
44
+ check('HTML has profile-footer section', html.includes('profile-footer'));
45
+ check('HTML has Toggle Status button', html.includes('Toggle Status'));
46
+ check('HTML has Save Profile button', html.includes('Save Profile'));
47
+ check('HTML has input elements for bind-value', html.includes('<input'));
48
+ check('HTML has First Name label', html.includes('First Name:'));
49
+ check('HTML has Last Name label', html.includes('Last Name:'));
50
+ // Note: bind-text content (e.g. "John Smith") is injected client-side
51
+ // during activation. SSR renders the structure; bind-text populates at runtime.
52
+
53
+ // ── 5. Model Mutation: Update first_name ─────────────────────────────
54
+ editor.data.model.set('first_name', 'Alice');
55
+ const updatedFullName = editor.data.model.get('full_name').value;
56
+ check('Computed full_name updates to "Alice Smith"', updatedFullName === 'Alice Smith');
57
+
58
+ // ── 6. Model Mutation: toggleStatus() ────────────────────────────────
59
+ editor.toggleStatus();
60
+ check('is_active toggled to false', editor.data.model.get('is_active').value === false);
61
+ check('Computed status_text = "Suspended Account"', editor.data.model.get('status_text').value === 'Suspended Account');
62
+
63
+ // ── 7. Toggle back ──────────────────────────────────────────────────
64
+ editor.toggleStatus();
65
+ check('is_active toggled back to true', editor.data.model.get('is_active').value === true);
66
+ check('Computed status_text back to "Active Account"', editor.data.model.get('status_text').value === 'Active Account');
67
+
68
+ // ── 8. Edge cases ───────────────────────────────────────────────────
69
+ editor.data.model.set('first_name', '');
70
+ check('Computed full_name with empty first = "Smith"', editor.data.model.get('full_name').value === 'Smith');
71
+
72
+ editor.data.model.set('last_name', '');
73
+ check('Computed full_name with both empty = ""', editor.data.model.get('full_name').value === '');
74
+
75
+ editor.data.model.set('first_name', 'Solo');
76
+ check('Computed full_name with empty last = "Solo"', editor.data.model.get('full_name').value === 'Solo');
77
+
78
+ // ── 9. CSS static property ──────────────────────────────────────────
79
+ check('UserProfileEditor.css defined', typeof UserProfileEditor.css === 'string' && UserProfileEditor.css.length > 100);
80
+ check('CSS contains .profile-card rule', UserProfileEditor.css.includes('.profile-card'));
81
+ check('CSS contains .active-state rule', UserProfileEditor.css.includes('.active-state'));
82
+ check('CSS contains .inactive-state rule', UserProfileEditor.css.includes('.inactive-state'));
83
+
84
+ // ── Verdict ─────────────────────────────────────────────────────────
85
+ console.log('\n═══════════════════════════════════════════');
86
+ console.log(`RESULTS: ${pass} passed, ${fail} failed`);
87
+ if (fail === 0) {
88
+ console.log('\n✅ VERDICT: All MVVM & Declarative API checks passed!');
89
+ } else {
90
+ console.log('\n⚠️ VERDICT: Some checks failed — review results above');
91
+ }
92
+ console.log('═══════════════════════════════════════════\n');
93
+
94
+ process.exit(fail > 0 ? 1 : 0);
@@ -0,0 +1,25 @@
1
+ [jsgui3-html] DEPRECATED: "FormField" is deprecated. Use "Form_Field" instead. This will be removed in v1.0.0.
2
+ [jsgui3-html] DEPRECATED: "PropertyEditor" is deprecated. Use "Property_Editor" instead. This will be removed in v1.0.0.
3
+
4
+ ═══ MVVM Declarative API Check ═══
5
+
6
+ ✅ Control initialized
7
+ ❌ Computed full_name working (John Smith)
8
+ ❌ Computed status_text working (Active Account)
9
+ ✅ HTML rendered without throwing
10
+ ❌ HTML contains full_name
11
+ ✅ HTML contains active-state class
12
+ ❌ HTML contains status_text
13
+ ❌ Computed dependency updates successfully when first_name changes
14
+ ❌ Re-rendered HTML reflects new name
15
+ ❌ Status is now inactive via toggleStatus()
16
+ ❌ Status text updated automatically
17
+ ❌ HTML reflects inactive-state class
18
+ ❌ HTML reflects Suspended Account text
19
+
20
+ ═══════════════════════════════════════════
21
+ RESULTS: 3 passed, 10 failed
22
+
23
+ ⚠️ VERDICT: Some checks failed — review results above
24
+ ═══════════════════════════════════════════
25
+
@@ -0,0 +1,27 @@
1
+ [jsgui3-html] DEPRECATED: "FormField" is deprecated. Use "Form_Field" instead. This will be removed in v1.0.0.
2
+ [jsgui3-html] DEPRECATED: "PropertyEditor" is deprecated. Use "Property_Editor" instead. This will be removed in v1.0.0.
3
+
4
+ ═══ MVVM Declarative API Check ═══
5
+
6
+ ✅ Control initialized
7
+ --- Debug fullName: John Smith
8
+ ❌ Computed full_name working (John Smith)
9
+ --- Debug statusText: Active Account
10
+ ❌ Computed status_text working (Active Account)
11
+ ✅ HTML rendered without throwing
12
+ ❌ HTML contains full_name
13
+ ✅ HTML contains active-state class
14
+ ❌ HTML contains status_text
15
+ ❌ Computed dependency updates successfully when first_name changes
16
+ ❌ Re-rendered HTML reflects new name
17
+ ❌ Status is now inactive via toggleStatus()
18
+ ❌ Status text updated automatically
19
+ ❌ HTML reflects inactive-state class
20
+ ❌ HTML reflects Suspended Account text
21
+
22
+ ═══════════════════════════════════════════
23
+ RESULTS: 3 passed, 10 failed
24
+
25
+ ⚠️ VERDICT: Some checks failed — review results above
26
+ ═══════════════════════════════════════════
27
+