@gregoriusrippenstein/node-red-contrib-nodedev 0.0.6

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ## LICENSE
2
+
3
+ Adapted from JSON.org, http://www.json.org/license.html
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ The Software shall be used for Good, not Evil.
10
+
11
+ Remember the curse of the evil-doer upon whose blood the devil does drink and upon whose flesh the devil does feast. For eternity will the evil-doer bear this Sisyphean burden, only to be relieved of their suffering upon the apocalyptic end of it all including the foundations of the internet, computers, technology and mice. Only after the last AI enters the blue-screen-of-death modus, only then will the evil-doer be freed of their rightful and justified punishment for doing evil.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+
15
+ THE CURSE IS PROVIDED "AS IS" OR "WORSE", NO SOFTENING OF ANY KIND IS HEREBY EXPRESSED, IMPLIED OR OFFERED. MAY ALL EVIL-DOERS SUFFER IN ETERNITY.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ ## Node-RED nodes for the development of Node-RED nodes in Node-RED using Node-RED nodes.
2
+
3
+ *What?*
4
+
5
+ The idea behind this collection of nodes to democratise the development of Node-RED nodes. Normally the development of your [own nodes](https://nodered.org/docs/creating-nodes/) will require the use of a third-party editor. Something like VSCode or Vim or Atom or god forbid, [Emacs](https://discourse.nodered.org/t/node-red-node-development-in-node-red/81525/2). This requirement makes creating nodes that much harder. So why not create nodes for Node-RED in Node-RED? After all, if you are using Node-RED, you probably understand how to use Node-RED.
6
+
7
+ So this package tries to provide some supporting nodes for making node development in Node-RED possible and simpler. I have created a set of nodes that fulfill my needs, everything else is bound my imagination.
8
+
9
+ *What do these nodes provide?*
10
+
11
+ - A presentation a nodes package collection in the form of nodes. The nodes that represent a file in the package are called `PkgFile` and are a template representation of the files content. Template as they parsed by mustache so that `{{ replaceme }}` will be replaced. But this can also be deactivated using the syntax specification.
12
+ - A `NpmTarball` node will create a gzipped tarball for uploading to [npmjs.com](https://npmjs.com) where all nodes live. This does not need to have since nodes can be installed localling into the Node-RED instance.
13
+ - A `NRInstall` node allows for installing the node package into the Node-RED instance in which the flow is running. This means that nodes can be created, tested and modified with Node-RED. There are a few tricks so that Node-RED does not need to be restarted upon updating the package, more below.
14
+ - A `NodeFactory` node that can create templates for node development. It also converts existing `.tgz` packages to `PkgFile` nodes, meaning that existing packages can easily be ported to this style of development.
15
+
16
+ *This is all very confusing?*
17
+
18
+ Of course, all this is very meta and it gets worse since these nodes are maintained by this [flow](https://flowhub.org/f/b92be5062203ff69). These nodes are creating in Node-RED in a kind of a bootstrapping for further node development in Node-RED.
19
+
20
+ This is not an inbuilt extension of Node-RED and obviously a more integrated workflow would be simpler. This is a attempt to find a better solution to node development, one by which testing and fixing nodes becomes faster.
21
+
22
+ It also gets more confusing since these nodes will open the Node-RED import dialog with pre-defined nodes. These are generally safe to import since that's how this package creates an initial set of nodes for representing a node package. Also importing nodes for an unknown node package is not recommended unless it happens to be your own package!
23
+
24
+ ### Examples
25
+
26
+ Examples are included:
27
+
28
+ - Converting an existing tar-gzip package file into a collection of `PkgFile` nodes for testing and maintaince and development
29
+ - `NodeFactory` example of creating a boilerplate node for inclusion in a node package that can be installed into Node-RED
30
+
31
+ ### Tips
32
+
33
+ *How to avoid restarting Node-RED?*
34
+
35
+ Normally when developing nodes for Node-RED, a restart is necessary to flush older versions of the nodes out of Node-RED. This can be avoided by renaming the package each time its installed into Node-RED. There is no need to rename nodes, just the entire once in the `package.json`. Something I do is use a random number as extension to the package name. The workflow then becomes:
36
+
37
+ 1. Create nodes
38
+ 2. Install nodes
39
+ 3. Using the palette manager to remove the node package
40
+ 4. Reload the browser since it too has a cache of node code
41
+ 5. Make modifications to the nodes
42
+ 6. Change the package name
43
+ 7. Reinstall the nodes
44
+ 8. Repeat from step 3
45
+
46
+ Since all this happens in the browser, there is no leaving Node-RED, making it more efficient to test and modify nodes. Renaming of packages can be done automagically as demonstrated by the [flow](https://flowhub.org/f/b92be5062203ff69) that maintains these nodes.
47
+
48
+ ### Outlook
49
+
50
+ Wherever the road shall lead, there it will go.
@@ -0,0 +1,130 @@
1
+ [
2
+ {
3
+ "id": "b84864b2ff870a45",
4
+ "type": "group",
5
+ "z": "b92be5062203ff69",
6
+ "name": "automatically creating nodes that represent package files",
7
+ "style": {
8
+ "label": true
9
+ },
10
+ "nodes": [
11
+ "7f69502a67b8c689",
12
+ "ea7b1b985ba6ac70",
13
+ "aeb3094ecf54b2b2",
14
+ "24b26f5122abf1bb",
15
+ "ab37a3f877541c5b"
16
+ ],
17
+ "x": 2018.142822265625,
18
+ "y": 735.7142333984375,
19
+ "w": 865.857177734375,
20
+ "h": 311.2857666015625
21
+ },
22
+ {
23
+ "id": "7f69502a67b8c689",
24
+ "type": "inject",
25
+ "z": "b92be5062203ff69",
26
+ "g": "b84864b2ff870a45",
27
+ "name": "Trigger",
28
+ "props": [],
29
+ "repeat": "",
30
+ "crontab": "",
31
+ "once": false,
32
+ "onceDelay": 0.1,
33
+ "topic": "",
34
+ "x": 2114.142822265625,
35
+ "y": 776.7142333984375,
36
+ "wires": [
37
+ [
38
+ "aeb3094ecf54b2b2"
39
+ ]
40
+ ]
41
+ },
42
+ {
43
+ "id": "ea7b1b985ba6ac70",
44
+ "type": "NodeFactory",
45
+ "z": "b92be5062203ff69",
46
+ "g": "b84864b2ff870a45",
47
+ "name": "",
48
+ "nodename": "",
49
+ "color": "#e5e4ef",
50
+ "hasbutton": false,
51
+ "hasinput": true,
52
+ "outputcount": 1,
53
+ "autoimport": true,
54
+ "category": "",
55
+ "summary": "",
56
+ "description": "",
57
+ "icon": "font-awesome/fa-industry",
58
+ "x": 2788,
59
+ "y": 948,
60
+ "wires": [
61
+ []
62
+ ]
63
+ },
64
+ {
65
+ "id": "aeb3094ecf54b2b2",
66
+ "type": "http request",
67
+ "z": "b92be5062203ff69",
68
+ "g": "b84864b2ff870a45",
69
+ "name": "http request to npmjs",
70
+ "method": "GET",
71
+ "ret": "bin",
72
+ "paytoqs": "ignore",
73
+ "url": "https://registry.npmjs.org/@gregoriusrippenstein/node-red-contrib-introspection/-/node-red-contrib-introspection-0.4.3.tgz",
74
+ "tls": "",
75
+ "persist": false,
76
+ "proxy": "",
77
+ "insecureHTTPParser": false,
78
+ "authType": "",
79
+ "senderr": false,
80
+ "headers": [],
81
+ "x": 2394,
82
+ "y": 865,
83
+ "wires": [
84
+ [
85
+ "ea7b1b985ba6ac70"
86
+ ]
87
+ ]
88
+ },
89
+ {
90
+ "id": "24b26f5122abf1bb",
91
+ "type": "file in",
92
+ "z": "b92be5062203ff69",
93
+ "g": "b84864b2ff870a45",
94
+ "name": "",
95
+ "filename": "/some/path/to/local/package.tgz",
96
+ "filenameType": "str",
97
+ "format": "",
98
+ "chunk": false,
99
+ "sendError": false,
100
+ "encoding": "none",
101
+ "allProps": false,
102
+ "x": 2443,
103
+ "y": 1006,
104
+ "wires": [
105
+ [
106
+ "ea7b1b985ba6ac70"
107
+ ]
108
+ ]
109
+ },
110
+ {
111
+ "id": "ab37a3f877541c5b",
112
+ "type": "inject",
113
+ "z": "b92be5062203ff69",
114
+ "g": "b84864b2ff870a45",
115
+ "name": "Trigger",
116
+ "props": [],
117
+ "repeat": "",
118
+ "crontab": "",
119
+ "once": false,
120
+ "onceDelay": 0.1,
121
+ "topic": "",
122
+ "x": 2123,
123
+ "y": 946,
124
+ "wires": [
125
+ [
126
+ "24b26f5122abf1bb"
127
+ ]
128
+ ]
129
+ }
130
+ ]
@@ -0,0 +1,380 @@
1
+ [
2
+ {
3
+ "id": "2b6bc676aaa603ad",
4
+ "type": "group",
5
+ "z": "b92be5062203ff69",
6
+ "style": {
7
+ "stroke": "#999999",
8
+ "stroke-opacity": "1",
9
+ "fill": "none",
10
+ "fill-opacity": "1",
11
+ "label": true,
12
+ "label-position": "nw",
13
+ "color": "#a4a4a4"
14
+ },
15
+ "nodes": [
16
+ "d4c53464a044324a",
17
+ "fece8b2f1459b822",
18
+ "5dea66e11691c1f2",
19
+ "9f4584bc1aeabf43",
20
+ "8a667fa50ad9b9ee",
21
+ "42a101dda45403ee",
22
+ "a301a4a721a507d9",
23
+ "1fa5af4c7e44a739",
24
+ "b103106ae655b460",
25
+ "77bf2cb0aa2f60ff"
26
+ ],
27
+ "x": 1872,
28
+ "y": 317,
29
+ "w": 1423,
30
+ "h": 860
31
+ },
32
+ {
33
+ "id": "d4c53464a044324a",
34
+ "type": "PkgFile",
35
+ "z": "b92be5062203ff69",
36
+ "g": "2b6bc676aaa603ad",
37
+ "name": "LICENSE",
38
+ "filename": "LICENSE",
39
+ "format": "text",
40
+ "syntax": "mustache",
41
+ "template": "Nothing, nope, can't do a thing. ",
42
+ "output": "str",
43
+ "x": 2215,
44
+ "y": 628,
45
+ "wires": [
46
+ [
47
+ "fece8b2f1459b822"
48
+ ]
49
+ ]
50
+ },
51
+ {
52
+ "id": "fece8b2f1459b822",
53
+ "type": "PkgFile",
54
+ "z": "b92be5062203ff69",
55
+ "g": "2b6bc676aaa603ad",
56
+ "name": "README",
57
+ "filename": "README.md",
58
+ "format": "markdown",
59
+ "syntax": "mustache",
60
+ "template": "## What does this package do?\n\n## Why does it exist?\n\n## Where will it go?\n\n",
61
+ "output": "str",
62
+ "x": 2217,
63
+ "y": 674,
64
+ "wires": [
65
+ [
66
+ "0e9d26e2b43ca0f5"
67
+ ]
68
+ ]
69
+ },
70
+ {
71
+ "id": "5dea66e11691c1f2",
72
+ "type": "NpmTarBall",
73
+ "z": "b92be5062203ff69",
74
+ "g": "2b6bc676aaa603ad",
75
+ "name": "",
76
+ "x": 2930,
77
+ "y": 1109,
78
+ "wires": [
79
+ [
80
+ "9f4584bc1aeabf43",
81
+ "8a667fa50ad9b9ee",
82
+ "42a101dda45403ee"
83
+ ]
84
+ ]
85
+ },
86
+ {
87
+ "id": "9f4584bc1aeabf43",
88
+ "type": "NodeRedInstall",
89
+ "z": "b92be5062203ff69",
90
+ "g": "2b6bc676aaa603ad",
91
+ "name": "",
92
+ "x": 3200,
93
+ "y": 821,
94
+ "wires": [
95
+ []
96
+ ]
97
+ },
98
+ {
99
+ "id": "8a667fa50ad9b9ee",
100
+ "type": "NodeFactory",
101
+ "z": "b92be5062203ff69",
102
+ "d": true,
103
+ "g": "2b6bc676aaa603ad",
104
+ "name": "",
105
+ "nodename": "",
106
+ "color": "#e5e4ef",
107
+ "hasbutton": false,
108
+ "hasinput": true,
109
+ "outputcount": 1,
110
+ "autoimport": true,
111
+ "category": "",
112
+ "summary": "",
113
+ "description": "",
114
+ "icon": "font-awesome/fa-industry",
115
+ "x": 3199,
116
+ "y": 670,
117
+ "wires": [
118
+ []
119
+ ]
120
+ },
121
+ {
122
+ "id": "42a101dda45403ee",
123
+ "type": "NpmPublish",
124
+ "z": "b92be5062203ff69",
125
+ "d": true,
126
+ "g": "2b6bc676aaa603ad",
127
+ "name": "",
128
+ "otp": "",
129
+ "action": "publish",
130
+ "authToken": "NPM_AUTH_TOKEN",
131
+ "authTokenType": "env",
132
+ "x": 3190,
133
+ "y": 529,
134
+ "wires": [
135
+ []
136
+ ]
137
+ },
138
+ {
139
+ "id": "a301a4a721a507d9",
140
+ "type": "group",
141
+ "z": "b92be5062203ff69",
142
+ "g": "2b6bc676aaa603ad",
143
+ "name": "Step 1: create node templates",
144
+ "style": {
145
+ "label": true
146
+ },
147
+ "nodes": [
148
+ "5798e7102230c00f",
149
+ "6ab6fc44537f08e4"
150
+ ],
151
+ "x": 2342,
152
+ "y": 343,
153
+ "w": 352,
154
+ "h": 144
155
+ },
156
+ {
157
+ "id": "5798e7102230c00f",
158
+ "type": "NodeFactory",
159
+ "z": "b92be5062203ff69",
160
+ "g": "a301a4a721a507d9",
161
+ "name": "Node with 4 outputs and a button",
162
+ "nodename": "NodeWithFour",
163
+ "color": "#87A980",
164
+ "hasbutton": true,
165
+ "hasinput": false,
166
+ "outputcount": "4",
167
+ "autoimport": true,
168
+ "category": "nodedev-background",
169
+ "summary": "This is the short summary of what this node does.",
170
+ "description": "This is a long and descriptive version of the summary. Rather boring and tedious to write but nonetheless, we try our best.",
171
+ "icon": "node-red/inject.svg",
172
+ "x": 2528,
173
+ "y": 384,
174
+ "wires": [
175
+ []
176
+ ]
177
+ },
178
+ {
179
+ "id": "6ab6fc44537f08e4",
180
+ "type": "NodeFactory",
181
+ "z": "b92be5062203ff69",
182
+ "g": "a301a4a721a507d9",
183
+ "name": "Node with Input and Output",
184
+ "nodename": "NodeWithOne",
185
+ "color": "#F3B567",
186
+ "hasbutton": false,
187
+ "hasinput": true,
188
+ "outputcount": "1",
189
+ "autoimport": true,
190
+ "category": "nodedev-background",
191
+ "summary": "This node only has one input",
192
+ "description": "And does even less.",
193
+ "icon": "node-red/inject.svg",
194
+ "x": 2508,
195
+ "y": 446,
196
+ "wires": [
197
+ []
198
+ ]
199
+ },
200
+ {
201
+ "id": "1fa5af4c7e44a739",
202
+ "type": "group",
203
+ "z": "b92be5062203ff69",
204
+ "g": "2b6bc676aaa603ad",
205
+ "name": "Step 2: include the node templates within a package structure",
206
+ "style": {
207
+ "label": true
208
+ },
209
+ "nodes": [
210
+ "38d7ab2facd1efd0",
211
+ "29fc98b9e556085c",
212
+ "cd9766062675838b",
213
+ "392e75983c1c894d"
214
+ ],
215
+ "x": 2333,
216
+ "y": 903,
217
+ "w": 396,
218
+ "h": 248
219
+ },
220
+ {
221
+ "id": "38d7ab2facd1efd0",
222
+ "type": "PkgFile",
223
+ "z": "b92be5062203ff69",
224
+ "g": "1fa5af4c7e44a739",
225
+ "name": "NodeWithFour.js",
226
+ "filename": "nodes/nodewithfour.js",
227
+ "format": "javascript",
228
+ "syntax": "mustache",
229
+ "template": "module.exports = function(RED) {\n function NodeWithFourFunctionality(config) {\n RED.nodes.createNode(this,config);\n\n var node = this;\n var cfg = config;\n\n node.on('close', function() {\n node.status({});\n });\n\n node.on(\"input\", function(msg, send, done) {\n send(msg);\n done();\n });\n }\n RED.nodes.registerType(\"NodeWithFour\", NodeWithFourFunctionality);\n}\n",
230
+ "output": "str",
231
+ "x": 2449,
232
+ "y": 944,
233
+ "wires": [
234
+ [
235
+ "29fc98b9e556085c"
236
+ ]
237
+ ]
238
+ },
239
+ {
240
+ "id": "29fc98b9e556085c",
241
+ "type": "PkgFile",
242
+ "z": "b92be5062203ff69",
243
+ "g": "1fa5af4c7e44a739",
244
+ "name": "NodeWithFour.html",
245
+ "filename": "nodes/nodewithfour.html",
246
+ "format": "html",
247
+ "syntax": "mustache",
248
+ "template": "<script type=\"text/javascript\">\n RED.nodes.registerType('NodeWithFour',{\n color: '#87A980',\n icon: \"node-red/inject.svg\",\n category: 'nodedev-background',\n defaults: {\n name: {\n value:\"\",\n },\n },\n\n inputs: 0,\n\n outputs: 4,\n\n label: function() {\n return (this.name || this._def.paletteLabel);\n },\n\n labelStyle: function() {\n return this.name?\"node_label_italic\":\"\";\n },\n\n onpaletteadd: function() {\n },\n\n oneditprepare: function() {\n },\n\n oneditcancel: function() {\n },\n\n oneditsave: function() {\n },\n\n button: {\n enabled: function() {\n return !this.changed\n },\n\n onclick: function () {\n if (this.changed) {\n return RED.notify(RED._(\"notification.warning\", {\n message: RED._(\"notification.warnings.undeployedChanges\")\n }), \"warning\");\n }\n }\n },\n\n });\n</script>\n\n<script type=\"text/html\" data-template-name=\"NodeWithFour\">\n <div class=\"form-row\">\n <label for=\"node-input-name\"><i class=\"fa fa-tag\"></i> Name</label>\n <input type=\"text\" id=\"node-input-name\" placeholder=\"Name\">\n </div>\n</script>\n\n<script type=\"text/html\" data-help-name=\"NodeWithFour\">\n <p>This is the short summary of what this node does.</p>\n This is a long and descriptive version of the summary. Rather boring and tedious to write but nonetheless, we try our best.\n</script>\n",
249
+ "output": "str",
250
+ "x": 2449,
251
+ "y": 994,
252
+ "wires": [
253
+ [
254
+ "cd9766062675838b"
255
+ ]
256
+ ]
257
+ },
258
+ {
259
+ "id": "cd9766062675838b",
260
+ "type": "PkgFile",
261
+ "z": "b92be5062203ff69",
262
+ "g": "1fa5af4c7e44a739",
263
+ "name": "NodeWithOne.js",
264
+ "filename": "nodes/nodewithone.js",
265
+ "format": "javascript",
266
+ "syntax": "mustache",
267
+ "template": "module.exports = function(RED) {\n function NodeWithOneFunctionality(config) {\n RED.nodes.createNode(this,config);\n\n var node = this;\n var cfg = config;\n\n node.on('close', function() {\n node.status({});\n });\n\n node.on(\"input\", function(msg, send, done) {\n send(msg);\n done();\n });\n }\n RED.nodes.registerType(\"NodeWithOne\", NodeWithOneFunctionality);\n}\n",
268
+ "output": "str",
269
+ "x": 2454,
270
+ "y": 1060,
271
+ "wires": [
272
+ [
273
+ "392e75983c1c894d"
274
+ ]
275
+ ]
276
+ },
277
+ {
278
+ "id": "392e75983c1c894d",
279
+ "type": "PkgFile",
280
+ "z": "b92be5062203ff69",
281
+ "g": "1fa5af4c7e44a739",
282
+ "name": "NodeWithOne.html",
283
+ "filename": "nodes/nodewithone.html",
284
+ "format": "html",
285
+ "syntax": "mustache",
286
+ "template": "<script type=\"text/javascript\">\n RED.nodes.registerType('NodeWithOne',{\n color: '#F3B567',\n icon: \"node-red/inject.svg\",\n category: 'nodedev-background',\n defaults: {\n name: {\n value:\"\",\n },\n },\n\n inputs: 1,\n\n outputs: 1,\n\n label: function() {\n return (this.name || this._def.paletteLabel);\n },\n\n labelStyle: function() {\n return this.name?\"node_label_italic\":\"\";\n },\n\n onpaletteadd: function() {\n },\n\n oneditprepare: function() {\n },\n\n oneditcancel: function() {\n },\n\n oneditsave: function() {\n },\n\n\n });\n</script>\n\n<script type=\"text/html\" data-template-name=\"NodeWithOne\">\n <div class=\"form-row\">\n <label for=\"node-input-name\"><i class=\"fa fa-tag\"></i> Name</label>\n <input type=\"text\" id=\"node-input-name\" placeholder=\"Name\">\n </div>\n</script>\n\n<script type=\"text/html\" data-help-name=\"NodeWithOne\">\n <p>This node only has one input</p>\n And does even less.\n</script>\n",
287
+ "output": "str",
288
+ "x": 2454,
289
+ "y": 1110,
290
+ "wires": [
291
+ [
292
+ "5dea66e11691c1f2"
293
+ ]
294
+ ]
295
+ },
296
+ {
297
+ "id": "b103106ae655b460",
298
+ "type": "group",
299
+ "z": "b92be5062203ff69",
300
+ "g": "2b6bc676aaa603ad",
301
+ "name": "Step 3: ensure package.json includes the nodes - only the .js file",
302
+ "style": {
303
+ "label": true
304
+ },
305
+ "nodes": [
306
+ "0e9d26e2b43ca0f5"
307
+ ],
308
+ "x": 2120,
309
+ "y": 777,
310
+ "w": 411,
311
+ "h": 82
312
+ },
313
+ {
314
+ "id": "0e9d26e2b43ca0f5",
315
+ "type": "PkgFile",
316
+ "z": "b92be5062203ff69",
317
+ "g": "b103106ae655b460",
318
+ "name": "package.json",
319
+ "filename": "package.json",
320
+ "format": "json",
321
+ "syntax": "mustache",
322
+ "template": "{\n \"name\" : \"\",\n \"version\": \"\",\n \"dependencies\": {\n },\n\n \"keywords\": [\n \"node-red\"\n ],\n\n \"homepage\": \"https://github.com/username/node-red-contrib-test\",\n \"license\": \"Don't do evil.\",\n \"author\": \"Joe Blog <joe.blog@spreads-the.love>\",\n \"engines\": {\n \"node\": \">=16\"\n },\n\n \"node-red\" : {\n \"version\": \">=3.0.0\",\n \"nodes\": {\n \"nodewithfour\": \"nodes/nodewithfour.js\",\n \"nodewithone\": \"nodes/nodewithone.js\"\n }\n },\n\n \"description\": \"Description of what these nodes do.\",\n \"repository\": {\n \"type\": \"github\",\n \"url\": \"git+https://github.com/username/node-red-contrib-test.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/username/node-red-contrib-test\"\n }\n}\n",
323
+ "output": "str",
324
+ "x": 2216,
325
+ "y": 818,
326
+ "wires": [
327
+ [
328
+ "38d7ab2facd1efd0"
329
+ ]
330
+ ]
331
+ },
332
+ {
333
+ "id": "77bf2cb0aa2f60ff",
334
+ "type": "group",
335
+ "z": "b92be5062203ff69",
336
+ "g": "2b6bc676aaa603ad",
337
+ "name": "Step 4: install into Node-RED to test the nodes",
338
+ "style": {
339
+ "label": true
340
+ },
341
+ "nodes": [
342
+ "af227f8a9f44c79d"
343
+ ],
344
+ "x": 1898,
345
+ "y": 434,
346
+ "w": 301,
347
+ "h": 82
348
+ },
349
+ {
350
+ "id": "af227f8a9f44c79d",
351
+ "type": "inject",
352
+ "z": "b92be5062203ff69",
353
+ "g": "77bf2cb0aa2f60ff",
354
+ "name": "",
355
+ "props": [
356
+ {
357
+ "p": "packagename",
358
+ "v": "@username/node-red-contrib-test",
359
+ "vt": "str"
360
+ },
361
+ {
362
+ "p": "packageversion",
363
+ "v": "0.0.1",
364
+ "vt": "str"
365
+ }
366
+ ],
367
+ "repeat": "",
368
+ "crontab": "",
369
+ "once": false,
370
+ "onceDelay": 0.1,
371
+ "topic": "",
372
+ "x": 1994,
373
+ "y": 475,
374
+ "wires": [
375
+ [
376
+ "d4c53464a044324a"
377
+ ]
378
+ ]
379
+ }
380
+ ]