@bonsae/nrg 0.16.0 → 0.18.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.
- package/README.md +112 -19
- package/package.json +38 -6
- package/server/index.cjs +38 -24
- package/server/resources/nrg-client.js +3667 -3521
- package/test/client/component/index.js +244 -0
- package/test/client/component/setup.js +201 -0
- package/test/client/e2e/index.js +2698 -0
- package/test/client/unit/index.js +200 -0
- package/test/client/unit/setup.js +199 -0
- package/test/{index.js → server/unit/index.js} +23 -8
- package/tsconfig/core/client.json +11 -0
- package/tsconfig/{server.json → core/server.json} +1 -1
- package/tsconfig/test/client/component.json +11 -0
- package/tsconfig/test/client/e2e.json +6 -0
- package/tsconfig/test/client/unit.json +6 -0
- package/tsconfig/test/server/unit.json +6 -0
- package/types/client.d.ts +66 -0
- package/types/server.d.ts +74 -58
- package/types/shims/form/components/node-red-config-input.vue.d.ts +15 -2
- package/types/shims/form/components/node-red-editor-input.vue.d.ts +18 -3
- package/types/shims/form/components/node-red-input.vue.d.ts +17 -5
- package/types/shims/form/components/node-red-json-schema-form.vue.d.ts +117 -19
- package/types/shims/form/components/node-red-select-input.vue.d.ts +15 -1
- package/types/shims/form/components/node-red-typed-input.vue.d.ts +52 -8
- package/types/test-client-component.d.ts +70 -0
- package/types/test-client-e2e.d.ts +152 -0
- package/types/test-client-unit.d.ts +52 -0
- package/types/{test.d.ts → test-server-unit.d.ts} +12 -2
- package/vite/index.js +15 -7
- package/tsconfig/client.json +0 -11
package/README.md
CHANGED
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
# nrg
|
|
13
13
|
|
|
14
|
-
Build Node-RED nodes with Vue 3, TypeScript, JSON Schema validations, Vite and
|
|
15
|
-
|
|
14
|
+
Build Node-RED nodes with Vue 3, TypeScript, JSON Schema validations, Vite and Vitest.
|
|
16
15
|
|
|
17
16
|
## Package Exports
|
|
18
17
|
|
|
@@ -20,9 +19,21 @@ Build Node-RED nodes with Vue 3, TypeScript, JSON Schema validations, Vite and V
|
|
|
20
19
|
| --- | --- |
|
|
21
20
|
| `@bonsae/nrg` | Root entry — `defineRuntimeSettings` |
|
|
22
21
|
| `@bonsae/nrg/server` | Server node classes, schema utilities, validation (`IONode`, `ConfigNode`, `defineIONode`, `defineConfigNode`, `defineModule`, `SchemaType`, `defineSchema`, `Infer`) |
|
|
23
|
-
| `@bonsae/nrg/client` | Client-side registration (`registerTypes`, `defineNode`) |
|
|
22
|
+
| `@bonsae/nrg/client` | Client-side registration (`registerTypes`, `defineNode`, `useFormNode`, `Infer`) |
|
|
24
23
|
| `@bonsae/nrg/vite` | Vite plugin for building and developing Node-RED packages |
|
|
25
|
-
| `@bonsae/nrg/
|
|
24
|
+
| `@bonsae/nrg/test/server/unit` | Server unit test helpers (`createNode`, `createRED`, `MockRED`) |
|
|
25
|
+
| `@bonsae/nrg/test/client/unit` | Client unit test config and mocks (`defaultConfig`, `createRED`, `createJQuery`) |
|
|
26
|
+
| `@bonsae/nrg/test/client/unit/setup` | Setup file that installs `RED` and `$` mocks on `window` |
|
|
27
|
+
| `@bonsae/nrg/test/client/component` | Client component test helpers (`createNode`, `defaultConfig`, `createRED`, `createJQuery`) |
|
|
28
|
+
| `@bonsae/nrg/test/client/component/setup` | Setup file that installs `RED` and `$` mocks on `window` with Vue i18n |
|
|
29
|
+
| `@bonsae/nrg/test/client/e2e` | Browser E2E test helpers (`NodeRedEditor`, `NodeRedField`, `setup`, `teardown`) |
|
|
30
|
+
| `@bonsae/nrg/tsconfig/base.json` | Base TypeScript configuration |
|
|
31
|
+
| `@bonsae/nrg/tsconfig/core/server.json` | Core server source tsconfig |
|
|
32
|
+
| `@bonsae/nrg/tsconfig/core/client.json` | Core client source tsconfig |
|
|
33
|
+
| `@bonsae/nrg/tsconfig/test/server/unit.json` | Server unit test tsconfig |
|
|
34
|
+
| `@bonsae/nrg/tsconfig/test/client/unit.json` | Client unit test tsconfig |
|
|
35
|
+
| `@bonsae/nrg/tsconfig/test/client/component.json` | Client component test tsconfig |
|
|
36
|
+
| `@bonsae/nrg/tsconfig/test/client/e2e.json` | Client E2E test tsconfig |
|
|
26
37
|
|
|
27
38
|
## Quick Start
|
|
28
39
|
|
|
@@ -32,7 +43,7 @@ pnpm add @bonsae/nrg
|
|
|
32
43
|
pnpm add -D vite vue
|
|
33
44
|
```
|
|
34
45
|
|
|
35
|
-
> `vite`
|
|
46
|
+
> `vite` and `vue` are dev dependencies because they are only needed at build time. Vue is included as a dependency of nrg and served automatically at runtime.
|
|
36
47
|
|
|
37
48
|
**vite.config.ts**
|
|
38
49
|
|
|
@@ -55,7 +66,7 @@ export const ConfigsSchema = defineSchema(
|
|
|
55
66
|
name: SchemaType.String({ default: "" }),
|
|
56
67
|
prefix: SchemaType.String({ default: "hello" }),
|
|
57
68
|
},
|
|
58
|
-
{ $id: "my-node:configs" }
|
|
69
|
+
{ $id: "my-node:configs" },
|
|
59
70
|
);
|
|
60
71
|
```
|
|
61
72
|
|
|
@@ -95,7 +106,7 @@ type Config = Infer<typeof ConfigsSchema>;
|
|
|
95
106
|
type Input = Infer<typeof InputSchema>;
|
|
96
107
|
type Output = Infer<typeof OutputSchema>;
|
|
97
108
|
|
|
98
|
-
export default class MyNode extends IONode<Config,
|
|
109
|
+
export default class MyNode extends IONode<Config, never, Input, Output> {
|
|
99
110
|
static readonly type = "my-node";
|
|
100
111
|
static readonly category = "function";
|
|
101
112
|
static readonly color: `#${string}` = "#ffffff";
|
|
@@ -131,16 +142,18 @@ See the [consumer template](https://github.com/AllanOricil/node-red-vue-template
|
|
|
131
142
|
|
|
132
143
|
## Testing
|
|
133
144
|
|
|
134
|
-
|
|
145
|
+
NRG provides four test libraries:
|
|
135
146
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
147
|
+
- `@bonsae/nrg/test/server/unit` — server-side unit tests
|
|
148
|
+
- `@bonsae/nrg/test/client/unit` — client-side unit tests (TypeScript logic)
|
|
149
|
+
- `@bonsae/nrg/test/client/component` — client component tests (Vue + browser)
|
|
150
|
+
- `@bonsae/nrg/test/client/e2e` — browser E2E tests (Playwright)
|
|
151
|
+
|
|
152
|
+
### Server Unit Tests
|
|
139
153
|
|
|
140
154
|
```typescript
|
|
141
|
-
// tests/my-node.test.ts
|
|
142
155
|
import { describe, it, expect } from "vitest";
|
|
143
|
-
import { createNode } from "@bonsae/nrg/test";
|
|
156
|
+
import { createNode } from "@bonsae/nrg/test/server/unit";
|
|
144
157
|
import MyNode from "../src/server/nodes/my-node";
|
|
145
158
|
|
|
146
159
|
describe("my-node", () => {
|
|
@@ -156,18 +169,98 @@ describe("my-node", () => {
|
|
|
156
169
|
});
|
|
157
170
|
```
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
|
|
172
|
+
### Client Unit Tests
|
|
173
|
+
|
|
174
|
+
Test client-side TypeScript logic (validation, utilities) with mocked `RED` and `$` globals:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// vitest.config.ts
|
|
178
|
+
import { defineConfig } from "vitest/config";
|
|
179
|
+
import { defaultConfig } from "@bonsae/nrg/test/client/unit";
|
|
180
|
+
|
|
181
|
+
export default defineConfig({
|
|
182
|
+
test: {
|
|
183
|
+
...defaultConfig,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// tests/client/unit/my-util.test.ts
|
|
190
|
+
import { describe, it, expect } from "vitest";
|
|
191
|
+
import { myUtil } from "../src/client/my-util";
|
|
192
|
+
|
|
193
|
+
describe("myUtil", () => {
|
|
194
|
+
it("works with RED globals", () => {
|
|
195
|
+
expect(myUtil("input")).toBe("expected");
|
|
196
|
+
});
|
|
197
|
+
});
|
|
161
198
|
```
|
|
162
199
|
|
|
200
|
+
### Client Component Tests
|
|
201
|
+
|
|
202
|
+
Test your Vue editor components with mocked Node-RED globals:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// vitest.config.ts
|
|
206
|
+
import { defineConfig } from "vitest/config";
|
|
207
|
+
import { playwright } from "@vitest/browser-playwright";
|
|
208
|
+
import vue from "@vitejs/plugin-vue";
|
|
209
|
+
import { defaultConfig } from "@bonsae/nrg/test/client/component";
|
|
210
|
+
|
|
211
|
+
export default defineConfig({
|
|
212
|
+
plugins: [vue()],
|
|
213
|
+
test: {
|
|
214
|
+
...defaultConfig,
|
|
215
|
+
browser: {
|
|
216
|
+
...defaultConfig.browser,
|
|
217
|
+
provider: playwright(),
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// tests/client/component/my-component.test.ts
|
|
225
|
+
import { describe, test, expect, vi } from "vitest";
|
|
226
|
+
import { render } from "vitest-browser-vue";
|
|
227
|
+
import { createNode } from "@bonsae/nrg/test/client/component";
|
|
228
|
+
import MyComponent from "../src/client/components/my-component.vue";
|
|
229
|
+
|
|
230
|
+
describe("MyComponent", () => {
|
|
231
|
+
test("renders with node props", async () => {
|
|
232
|
+
const { node } = createNode({ name: "test" });
|
|
233
|
+
const screen = render(MyComponent, {
|
|
234
|
+
props: { node },
|
|
235
|
+
});
|
|
236
|
+
await expect.element(screen.getByText("test")).toBeInTheDocument();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("calls RED.editor API", async () => {
|
|
240
|
+
const { node, RED } = createNode();
|
|
241
|
+
render(MyComponent, { props: { node, value: "" } });
|
|
242
|
+
expect(RED.editor.createEditor).toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
See the [testing guide](https://bonsaedev.github.io/nrg/guide/testing) for full API reference.
|
|
248
|
+
|
|
163
249
|
## Development
|
|
164
250
|
|
|
165
251
|
```bash
|
|
166
252
|
pnpm install
|
|
167
|
-
pnpm build
|
|
168
|
-
pnpm
|
|
169
|
-
pnpm
|
|
170
|
-
pnpm
|
|
253
|
+
pnpm build # build all (server, client, vite plugin, test libs)
|
|
254
|
+
pnpm validate # type-check + lint + format check
|
|
255
|
+
pnpm validate:tsc # type-check all tsconfigs
|
|
256
|
+
pnpm validate:lint # eslint
|
|
257
|
+
pnpm validate:format # prettier check
|
|
258
|
+
pnpm test # run all tests
|
|
259
|
+
pnpm test:core:server:unit # server unit tests
|
|
260
|
+
pnpm test:core:client:unit # client unit tests
|
|
261
|
+
pnpm test:core:client:component # client component tests
|
|
262
|
+
pnpm test:core:client:e2e # client E2E tests
|
|
263
|
+
pnpm docs:dev # start docs dev server
|
|
171
264
|
```
|
|
172
265
|
|
|
173
266
|
## License
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bonsae/nrg",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "NRG framework — build Node-RED nodes with Vue 3, TypeScript, and JSON Schema",
|
|
5
5
|
"author": "Allan Oricil <allanoricil@duck.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"homepage": "https://bonsaedev.github.io/nrg/",
|
|
8
9
|
"repository": {
|
|
9
10
|
"url": "https://github.com/bonsaedev/nrg",
|
|
10
11
|
"type": "git"
|
|
@@ -16,6 +17,19 @@
|
|
|
16
17
|
"node": ">=20.19",
|
|
17
18
|
"pnpm": ">=10.11.0"
|
|
18
19
|
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"node-red",
|
|
22
|
+
"vue",
|
|
23
|
+
"vue3",
|
|
24
|
+
"typescript",
|
|
25
|
+
"json-schema",
|
|
26
|
+
"vite",
|
|
27
|
+
"vitest",
|
|
28
|
+
"iot",
|
|
29
|
+
"automation",
|
|
30
|
+
"low-code",
|
|
31
|
+
"framework"
|
|
32
|
+
],
|
|
19
33
|
"exports": {
|
|
20
34
|
".": {
|
|
21
35
|
"types": "./types/index.d.ts",
|
|
@@ -33,13 +47,31 @@
|
|
|
33
47
|
"types": "./types/vite.d.ts",
|
|
34
48
|
"default": "./vite/index.js"
|
|
35
49
|
},
|
|
36
|
-
"./test": {
|
|
37
|
-
"types": "./types/test.d.ts",
|
|
38
|
-
"default": "./test/index.js"
|
|
50
|
+
"./test/server/unit": {
|
|
51
|
+
"types": "./types/test-server-unit.d.ts",
|
|
52
|
+
"default": "./test/server/unit/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./test/client/component": {
|
|
55
|
+
"types": "./types/test-client-component.d.ts",
|
|
56
|
+
"default": "./test/client/component/index.js"
|
|
57
|
+
},
|
|
58
|
+
"./test/client/component/setup": "./test/client/component/setup.js",
|
|
59
|
+
"./test/client/unit": {
|
|
60
|
+
"types": "./types/test-client-unit.d.ts",
|
|
61
|
+
"default": "./test/client/unit/index.js"
|
|
62
|
+
},
|
|
63
|
+
"./test/client/unit/setup": "./test/client/unit/setup.js",
|
|
64
|
+
"./test/client/e2e": {
|
|
65
|
+
"types": "./types/test-client-e2e.d.ts",
|
|
66
|
+
"default": "./test/client/e2e/index.js"
|
|
39
67
|
},
|
|
40
68
|
"./tsconfig/base.json": "./tsconfig/base.json",
|
|
41
|
-
"./tsconfig/
|
|
42
|
-
"./tsconfig/
|
|
69
|
+
"./tsconfig/core/server.json": "./tsconfig/core/server.json",
|
|
70
|
+
"./tsconfig/core/client.json": "./tsconfig/core/client.json",
|
|
71
|
+
"./tsconfig/test/server/unit.json": "./tsconfig/test/server/unit.json",
|
|
72
|
+
"./tsconfig/test/client/component.json": "./tsconfig/test/client/component.json",
|
|
73
|
+
"./tsconfig/test/client/unit.json": "./tsconfig/test/client/unit.json",
|
|
74
|
+
"./tsconfig/test/client/e2e.json": "./tsconfig/test/client/e2e.json"
|
|
43
75
|
},
|
|
44
76
|
"peerDependencies": {
|
|
45
77
|
"vite": "^6.0.0",
|
package/server/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
ErrorPortSchema: () => ErrorPortSchema,
|
|
36
36
|
IONode: () => IONode,
|
|
37
37
|
Node: () => Node,
|
|
38
|
+
NodeSourceSchema: () => NodeSourceSchema,
|
|
38
39
|
NrgError: () => NrgError,
|
|
39
40
|
SchemaType: () => SchemaType,
|
|
40
41
|
StatusPortSchema: () => StatusPortSchema,
|
|
@@ -449,6 +450,11 @@ var IONode = class extends Node {
|
|
|
449
450
|
`outputsSchema record key "${key}" in ${this.type} looks numeric. Use descriptive string names (e.g. "success", "failure") to avoid JavaScript object key ordering issues.`
|
|
450
451
|
);
|
|
451
452
|
}
|
|
453
|
+
if (key === "error" || key === "complete" || key === "status") {
|
|
454
|
+
throw new NrgError(
|
|
455
|
+
`outputsSchema record key "${key}" in ${this.type} is reserved for built-in ports. Use a different name (e.g. "failed" instead of "error").`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
452
458
|
}
|
|
453
459
|
return keys.length;
|
|
454
460
|
}
|
|
@@ -579,10 +585,11 @@ var IONode = class extends Node {
|
|
|
579
585
|
}
|
|
580
586
|
this.log("Output is valid");
|
|
581
587
|
}
|
|
588
|
+
const out = Array.isArray(msg) ? msg.slice(0, this.baseOutputs) : msg;
|
|
582
589
|
if (this.#send) {
|
|
583
|
-
this.#send(
|
|
590
|
+
this.#send(out);
|
|
584
591
|
} else {
|
|
585
|
-
this.node.send(
|
|
592
|
+
this.node.send(out);
|
|
586
593
|
}
|
|
587
594
|
}
|
|
588
595
|
// --- Built-in port management ---
|
|
@@ -599,16 +606,20 @@ var IONode = class extends Node {
|
|
|
599
606
|
}
|
|
600
607
|
/**
|
|
601
608
|
* Send a message to a specific output port by index or name.
|
|
602
|
-
* Built-in port `"status"` is resolved automatically based on the node's
|
|
603
|
-
* built-in port configuration.
|
|
604
609
|
* Custom named ports are resolved from `outputsSchema` when it is a record.
|
|
605
610
|
* Numeric indices refer to the base output ports (0-based).
|
|
606
611
|
*
|
|
607
|
-
*
|
|
608
|
-
* cannot be sent to directly.
|
|
609
|
-
*
|
|
612
|
+
* Built-in ports (`"error"`, `"complete"`, `"status"`) are managed by the
|
|
613
|
+
* framework and cannot be sent to directly. Use `this.status()` for status,
|
|
614
|
+
* throw an error or call `this.error()` for the error port, and the complete
|
|
615
|
+
* port is sent automatically on successful input processing.
|
|
610
616
|
*/
|
|
611
617
|
sendToPort(port, msg) {
|
|
618
|
+
if (port === "error" || port === "complete" || port === "status") {
|
|
619
|
+
throw new NrgError(
|
|
620
|
+
`sendToPort("${port}") is not allowed. Built-in ports are managed by the framework.`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
612
623
|
this.#sendToPort(port, msg);
|
|
613
624
|
}
|
|
614
625
|
#sendToPort(port, msg) {
|
|
@@ -652,10 +663,9 @@ var IONode = class extends Node {
|
|
|
652
663
|
name: this.name
|
|
653
664
|
};
|
|
654
665
|
}
|
|
655
|
-
status(status
|
|
666
|
+
status(status) {
|
|
656
667
|
this.node.status(status);
|
|
657
668
|
this.#sendToPort("status", {
|
|
658
|
-
...data,
|
|
659
669
|
status,
|
|
660
670
|
source: this.#nodeSource()
|
|
661
671
|
});
|
|
@@ -1185,21 +1195,24 @@ var CompletePortSchema = SchemaType.Object({
|
|
|
1185
1195
|
})
|
|
1186
1196
|
});
|
|
1187
1197
|
var StatusPortSchema = SchemaType.Object({
|
|
1188
|
-
status: SchemaType.
|
|
1189
|
-
|
|
1190
|
-
SchemaType.
|
|
1191
|
-
SchemaType.
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
SchemaType.
|
|
1197
|
-
SchemaType.
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1198
|
+
status: SchemaType.Union([
|
|
1199
|
+
SchemaType.Object({
|
|
1200
|
+
fill: SchemaType.Optional(
|
|
1201
|
+
SchemaType.Union([
|
|
1202
|
+
SchemaType.Literal("red"),
|
|
1203
|
+
SchemaType.Literal("green")
|
|
1204
|
+
])
|
|
1205
|
+
),
|
|
1206
|
+
shape: SchemaType.Optional(
|
|
1207
|
+
SchemaType.Union([
|
|
1208
|
+
SchemaType.Literal("dot"),
|
|
1209
|
+
SchemaType.Literal("string")
|
|
1210
|
+
])
|
|
1211
|
+
),
|
|
1212
|
+
text: SchemaType.Optional(SchemaType.String())
|
|
1213
|
+
}),
|
|
1214
|
+
SchemaType.String()
|
|
1215
|
+
]),
|
|
1203
1216
|
source: NodeSourceSchema
|
|
1204
1217
|
});
|
|
1205
1218
|
|
|
@@ -1214,6 +1227,7 @@ function defineModule(definition) {
|
|
|
1214
1227
|
ErrorPortSchema,
|
|
1215
1228
|
IONode,
|
|
1216
1229
|
Node,
|
|
1230
|
+
NodeSourceSchema,
|
|
1217
1231
|
NrgError,
|
|
1218
1232
|
SchemaType,
|
|
1219
1233
|
StatusPortSchema,
|