Compare commits

..

46 Commits

Author SHA1 Message Date
Nick O'Leary
46fdf56c79 Allow nodes to return additional history entries in onEditSave 2024-05-20 16:41:44 +01:00
Nick O'Leary
f55ee6e665 Merge pull request #4685 from node-red/4683-preserve-full-error-obj
Pass full error object in Function node and copy over cause property
2024-05-13 15:25:02 +01:00
Nick O'Leary
03648dc7e8 Update tests for changed function node low-level output 2024-05-09 17:25:47 +01:00
Nick O'Leary
66a667fe58 Pass full error object in Function node and copy over cause property
Fixes #4683
2024-05-09 16:48:51 +01:00
Nick O'Leary
1bb3a0eca5 Merge pull request #4534 from patlux/master
Replacing vm.createScript in favour of vm.Script
2024-05-09 15:19:45 +01:00
Nick O'Leary
08927dfb55 Merge pull request #4684 from node-red/4363-autoLogin-redirect-loop
Avoid login loops when autoLogin enabled but login fails
2024-05-08 15:48:21 +01:00
Nick O'Leary
b27483de9c Avoid login loops when autoLogin enabled but login fails
Fixes #4363
2024-05-08 15:09:51 +01:00
Nick O'Leary
211d420fb2 Merge pull request #4667 from node-red/fix-subflow-property-undo
Fix undo of subflow env property edits
2024-04-23 23:45:46 +02:00
Nick O'Leary
b8ca4665c1 Merge pull request #4660 from JoshuaCWebDeveloper/patch-1
Fix three error typos in monaco.js
2024-04-23 23:45:16 +02:00
Nick O'Leary
960af87fb0 Ensure subflow change state is cleared after deploy 2024-04-23 21:17:35 +02:00
Nick O'Leary
de7339ae97 Fix undo of subflow env property edits 2024-04-23 20:39:14 +02:00
Stephen McLaughlin
0995af62b6 Merge pull request #4664 from ZJvandeWeg/patch-3
docs: Add closing paragraph tag
2024-04-20 13:54:37 +01:00
Zeger-Jan van de Weg
c2e03a40b4 docs: Add closing paragraph tag
Minor change that only improves xpath parsing.
2024-04-20 14:20:59 +02:00
Joshua Carter
c855050bcf Fix three error typos in monaco.js 2024-04-15 08:09:26 -07:00
Nick O'Leary
29ed5b2792 Merge pull request #4655 from node-red/rel319
Bump for 3.1.9 release
2024-04-11 19:22:24 +01:00
Nick O'Leary
e39216e65a Bump for 3.1.9 release 2024-04-11 19:15:46 +01:00
Nick O'Leary
7ac7f9b4c8 Merge pull request #4654 from node-red/fix-subflow-recursion-check
Prevent subflow being added to itself
2024-04-11 19:12:43 +01:00
Stephen McLaughlin
4709eb9d49 Merge pull request #4652 from node-red/fix-windows-spawn
Fix use of spawn on windows with cmd files
2024-04-11 17:51:13 +01:00
Nick O'Leary
c13b8266dd Prevent subflow being added to itself 2024-04-11 17:05:10 +01:00
Nick O'Leary
bd58431603 Fix use of spawn on windows with cmd files 2024-04-11 14:40:29 +01:00
Nick O'Leary
9a3cb0b2b5 Merge pull request #4640 from node-red/fix-subflow-init-err
Guard refresh of unknown subflow
2024-04-02 20:06:47 +01:00
Nick O'Leary
6beae5a806 Merge pull request #4642 from node-red/4641-fix-subflow-module-debug-logging
Fix subflow module sending messages to debug sidebar
2024-04-02 20:06:31 +01:00
Nick O'Leary
a0636632a1 Fix subflow module sending messages to debug sidebar
Fixes #4641
2024-04-02 17:42:19 +01:00
Nick O'Leary
5dfa47ab6c Guard refresh of unknown subflow 2024-04-02 15:54:34 +01:00
Nick O'Leary
ade4679e8c Merge pull request #4636 from node-red/rel318
Bump for 3.1.8
2024-03-28 15:23:07 +00:00
Nick O'Leary
410b938442 Bump for 3.1.8 2024-03-28 15:02:02 +00:00
Nick O'Leary
19dcc3a683 Merge pull request #4632 from node-red/4625-sf-env-err-handling
Add validation and error handling on subflow instance properties
2024-03-28 11:10:28 +00:00
Nick O'Leary
20d067c1ea Merge pull request #4633 from node-red/4617-hide-library-context-options
Hide import/export context menu if disabled in theme
2024-03-28 11:10:14 +00:00
Nick O'Leary
9526566799 Hide import/export context menu if disabled in theme 2024-03-28 11:00:10 +00:00
Nick O'Leary
0b9dd82c91 Merge pull request #4631 from node-red/4626-subflow-change-notification
Show change indicator on subflow tabs
2024-03-27 19:10:39 +00:00
Nick O'Leary
19213434f9 Add validation to subflow instance env properties 2024-03-27 19:08:25 +00:00
Nick O'Leary
014691346a Handle malformed env var values and log errors 2024-03-27 18:23:12 +00:00
Nick O'Leary
6738b95c29 Merge pull request #4630 from node-red/bump-express
Bump dependencies
2024-03-27 18:11:54 +00:00
Nick O'Leary
6a8230ec1e Show change icon on subflow tabs
Fixes #4626
2024-03-27 18:10:04 +00:00
Nick O'Leary
5679d264b6 Bump dependencies 2024-03-27 18:00:06 +00:00
Nick O'Leary
37265cf4ef Merge pull request #4619 from node-red/4600-reset-workspace-index
Reset workspace index when clearing nodes
2024-03-21 17:38:39 +00:00
Nick O'Leary
8a63275989 Merge pull request #4613 from kazuhitoyokoi/master-fixglobalconfig
Remove typo in global config
2024-03-21 16:54:01 +00:00
Nick O'Leary
7fc64a84e8 Bump test helper 2024-03-21 15:16:49 +00:00
Nick O'Leary
02f7cdd5aa Ensure all httpRequest test servers are ready before tests run 2024-03-21 15:03:37 +00:00
Nick O'Leary
d7dcceef60 Add debug for http tests 2024-03-21 11:32:29 +00:00
Nick O'Leary
ae5e1570ae Reset workspace index when clearing nodes
Fixes #4600
2024-03-21 11:14:34 +00:00
Kazuhito Yokoi
3ca045394a Remove typo in global config 2024-03-16 18:51:13 +09:00
Patrick Wozniak
28907082f1 fix usage of vm.Script() 2024-01-21 02:16:00 +01:00
Patrick Wozniak
f83174c40a fix use of vm.Script by adding new 2024-01-21 01:23:07 +01:00
Patrick Wozniak
ec062d008f replace vm.createScript in favor of vm.Script 2024-01-21 01:13:00 +01:00
Patrick Wozniak
a587655a5a adding pollyfill for vm.createScript
adds support for bun.sh
2024-01-21 01:00:02 +01:00
30 changed files with 365 additions and 198 deletions

View File

@@ -1,3 +1,19 @@
#### 3.1.9: Maintenance Release
- Prevent subflow being added to itself (#4654) @knolleary
- Fix use of spawn on windows with cmd files (#4652) @knolleary
- Guard refresh of unknown subflow (#4640) @knolleary
- Fix subflow module sending messages to debug sidebar (#4642) @knolleary
#### 3.1.8: Maintenance Release
- Add validation and error handling on subflow instance properties (#4632) @knolleary
- Hide import/export context menu if disabled in theme (#4633) @knolleary
- Show change indicator on subflow tabs (#4631) @knolleary
- Bump dependencies (#4630) @knolleary
- Reset workspace index when clearing nodes (#4619) @knolleary
- Remove typo in global config (#4613) @kazuhitoyokoi
#### 3.1.7: Maintenance Release #### 3.1.7: Maintenance Release
- Add Japanese translation for v3.1.6 (#4603) @kazuhitoyokoi - Add Japanese translation for v3.1.6 (#4603) @kazuhitoyokoi

View File

@@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "3.1.7", "version": "3.1.9",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org", "homepage": "https://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -41,7 +41,7 @@
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cronosjs": "1.7.1",
"denque": "2.1.0", "denque": "2.1.0",
"express": "4.18.2", "express": "4.19.2",
"express-session": "1.17.3", "express-session": "1.17.3",
"form-data": "4.0.0", "form-data": "4.0.0",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
@@ -64,7 +64,7 @@
"mqtt": "4.3.7", "mqtt": "4.3.7",
"multer": "1.4.5-lts.1", "multer": "1.4.5-lts.1",
"mustache": "4.2.0", "mustache": "4.2.0",
"node-red-admin": "^3.1.2", "node-red-admin": "^3.1.3",
"node-watch": "0.7.4", "node-watch": "0.7.4",
"nopt": "5.0.0", "nopt": "5.0.0",
"oauth2orize": "1.11.1", "oauth2orize": "1.11.1",
@@ -74,7 +74,7 @@
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"semver": "7.5.4", "semver": "7.5.4",
"tar": "6.1.13", "tar": "6.2.1",
"tough-cookie": "4.1.3", "tough-cookie": "4.1.3",
"uglify-js": "3.17.4", "uglify-js": "3.17.4",
"uuid": "9.0.0", "uuid": "9.0.0",
@@ -112,7 +112,7 @@
"mermaid": "^10.4.0", "mermaid": "^10.4.0",
"minami": "1.2.3", "minami": "1.2.3",
"mocha": "9.2.2", "mocha": "9.2.2",
"node-red-node-test-helper": "^0.3.2", "node-red-node-test-helper": "^0.3.3",
"nodemon": "2.0.20", "nodemon": "2.0.20",
"proxy": "^1.0.2", "proxy": "^1.0.2",
"sass": "1.62.1", "sass": "1.62.1",

View File

@@ -205,9 +205,10 @@ function genericStrategy(adminApp,strategy) {
passport.use(new strategy.strategy(options, verify)); passport.use(new strategy.strategy(options, verify));
adminApp.get('/auth/strategy', adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, {session:false, passport.authenticate(strategy.name, {
session:false,
failureMessage: true, failureMessage: true,
failureRedirect: settings.httpAdminRoot failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
}), }),
completeGenerateStrategyAuth, completeGenerateStrategyAuth,
handleStrategyError handleStrategyError
@@ -221,7 +222,7 @@ function genericStrategy(adminApp,strategy) {
passport.authenticate(strategy.name, { passport.authenticate(strategy.name, {
session:false, session:false,
failureMessage: true, failureMessage: true,
failureRedirect: settings.httpAdminRoot failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
}), }),
completeGenerateStrategyAuth, completeGenerateStrategyAuth,
handleStrategyError handleStrategyError

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-api", "name": "@node-red/editor-api",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,14 +16,14 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "3.1.7", "@node-red/util": "3.1.9",
"@node-red/editor-client": "3.1.7", "@node-red/editor-client": "3.1.9",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.20.2", "body-parser": "1.20.2",
"clone": "2.1.2", "clone": "2.1.2",
"cors": "2.8.5", "cors": "2.8.5",
"express-session": "1.17.3", "express-session": "1.17.3",
"express": "4.18.2", "express": "4.19.2",
"memorystore": "1.6.7", "memorystore": "1.6.7",
"mime": "3.0.0", "mime": "3.0.0",
"multer": "1.4.5-lts.1", "multer": "1.4.5-lts.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-client", "name": "@node-red/editor-client",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -547,12 +547,16 @@ RED.nodes = (function() {
* @param {String} z tab id * @param {String} z tab id
*/ */
checkTabState: function (z) { checkTabState: function (z) {
const ws = workspaces[z] const ws = workspaces[z] || subflows[z]
if (ws) { if (ws) {
const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0 const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0
if (Boolean(ws.contentsChanged) !== contentsChanged) { if (Boolean(ws.contentsChanged) !== contentsChanged) {
ws.contentsChanged = contentsChanged ws.contentsChanged = contentsChanged
RED.events.emit("flows:change", ws); if (ws.type === 'tab') {
RED.events.emit("flows:change", ws);
} else {
RED.events.emit("subflows:change", ws);
}
} }
} }
} }
@@ -1025,7 +1029,22 @@ RED.nodes = (function() {
RED.nodes.registerType("subflow:"+sf.id, { RED.nodes.registerType("subflow:"+sf.id, {
defaults:{ defaults:{
name:{value:""}, name:{value:""},
env:{value:[]} env:{value:[], validate: function(value) {
const errors = []
if (value) {
value.forEach(env => {
const r = RED.utils.validateTypedProperty(env.value, env.type)
if (r !== true) {
errors.push(env.name+': '+r)
}
})
}
if (errors.length === 0) {
return true
} else {
return errors
}
}}
}, },
icon: function() { return sf.icon||"subflow.svg" }, icon: function() { return sf.icon||"subflow.svg" },
category: sf.category || "subflows", category: sf.category || "subflows",

View File

@@ -118,10 +118,16 @@ RED.contextMenu = (function () {
onselect: 'core:split-wire-with-link-nodes', onselect: 'core:split-wire-with-link-nodes',
disabled: !canEdit || !hasLinks disabled: !canEdit || !hasLinks
}, },
null, null
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
) )
if (RED.settings.theme("menu.menu-item-import-library", true)) {
insertOptions.push(
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
)
}
if (hasSelection && canEdit) { if (hasSelection && canEdit) {
const nodeOptions = [] const nodeOptions = []
if (!hasMultipleSelection && !isGroup) { if (!hasMultipleSelection && !isGroup) {
@@ -194,8 +200,14 @@ RED.contextMenu = (function () {
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
{ onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete }, { onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete },
{ onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete }, { onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete },
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, )
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }, if (RED.settings.theme("menu.menu-item-export-library", true)) {
menuItems.push(
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }
)
}
menuItems.push(
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }
) )
} }

View File

@@ -612,7 +612,10 @@ RED.deploy = (function() {
} }
}); });
RED.nodes.eachSubflow(function (subflow) { RED.nodes.eachSubflow(function (subflow) {
subflow.changed = false; if (subflow.changed) {
subflow.changed = false;
RED.events.emit("subflows:change", subflow);
}
}); });
RED.nodes.eachWorkspace(function (ws) { RED.nodes.eachWorkspace(function (ws) {
if (ws.changed || ws.added) { if (ws.changed || ws.added) {

View File

@@ -741,9 +741,16 @@ RED.editor = (function() {
} }
try { try {
var rc = editing_node._def.oneditsave.call(editing_node); const rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) { if (rc === true) {
editState.changed = true; editState.changed = true;
} else if (typeof rc === 'object' && rc !== null ) {
if (rc.changed === true) {
editState.changed = true
}
if (Array.isArray(rc.history) && rc.history.length > 0) {
editState.history = rc.history
}
} }
} catch(err) { } catch(err) {
console.warn("oneditsave",editing_node.id,editing_node.type,err.toString()); console.warn("oneditsave",editing_node.id,editing_node.type,err.toString());
@@ -1015,7 +1022,7 @@ RED.editor = (function() {
} }
}); });
} }
var historyEvent = { let historyEvent = {
t:'edit', t:'edit',
node:editing_node, node:editing_node,
changes:editState.changes, changes:editState.changes,
@@ -1031,6 +1038,15 @@ RED.editor = (function() {
instances:subflowInstances instances:subflowInstances
} }
} }
if (editState.history) {
historyEvent = {
t: 'multi',
events: [ historyEvent, ...editState.history ],
dirty: wasDirty
}
}
RED.history.push(historyEvent); RED.history.push(historyEvent);
} }
editing_node.dirty = true; editing_node.dirty = true;
@@ -1623,8 +1639,8 @@ RED.editor = (function() {
} }
if (!isSameObj(old_env, new_env)) { if (!isSameObj(old_env, new_env)) {
editing_node.env = new_env;
editState.changes.env = editing_node.env; editState.changes.env = editing_node.env;
editing_node.env = new_env;
editState.changed = true; editState.changed = true;
} }

View File

@@ -514,7 +514,7 @@ RED.editor.codeEditor.monaco = (function() {
_monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions); _monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions);
if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); } if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up json options", err) console.warn("monaco - Error setting up json options", error)
} }
} }
@@ -526,7 +526,7 @@ RED.editor.codeEditor.monaco = (function() {
if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); } if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); }
if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); } if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up html options", err) console.warn("monaco - Error setting up html options", error)
} }
} }
@@ -546,7 +546,7 @@ RED.editor.codeEditor.monaco = (function() {
if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); } if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); }
if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); } if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up CSS/SCSS/LESS options", err) console.warn("monaco - Error setting up CSS/SCSS/LESS options", error)
} }
} }

View File

@@ -158,8 +158,10 @@ RED.sidebar.help = (function() {
function refreshSubflow(sf) { function refreshSubflow(sf) {
var item = treeList.treeList('get',"node-type:subflow:"+sf.id); var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
item.subflowLabel = sf._def.label().toLowerCase(); if (item) {
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()})); item.subflowLabel = sf._def.label().toLowerCase();
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
}
} }
function hideTOC() { function hideTOC() {

View File

@@ -646,120 +646,128 @@ RED.view = (function() {
} }
d3.event = event; d3.event = event;
var selected_tool = $(ui.draggable[0]).attr("data-palette-type"); var selected_tool = $(ui.draggable[0]).attr("data-palette-type");
var result = createNode(selected_tool);
if (!result) {
return;
}
var historyEvent = result.historyEvent;
var nn = RED.nodes.add(result.node);
var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
nn.l = showLabel;
}
var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
var helperWidth = ui.helper.width();
var helperHeight = ui.helper.height();
var mousePos = d3.touches(this)[0]||d3.mouse(this);
try { try {
var isLink = (nn.type === "link in" || nn.type === "link out") var result = createNode(selected_tool);
var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink; if (!result) {
return;
var label = RED.utils.getNodeLabel(nn, nn.type);
var labelParts = getLabelParts(label, "red-ui-flow-node-label");
if (hideLabel) {
nn.w = node_height;
nn.h = Math.max(node_height,(nn.outputs || 0) * 15);
} else {
nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) );
nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30);
} }
} catch(err) { var historyEvent = result.historyEvent;
} var nn = RED.nodes.add(result.node);
mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]); var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]); if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
mousePos[1] /= scaleFactor; nn.l = showLabel;
mousePos[0] /= scaleFactor; }
nn.x = mousePos[0]; var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
nn.y = mousePos[1]; var helperWidth = ui.helper.width();
var helperHeight = ui.helper.height();
var mousePos = d3.touches(this)[0]||d3.mouse(this);
var minX = nn.w/2 -5; try {
if (nn.x < minX) { var isLink = (nn.type === "link in" || nn.type === "link out")
nn.x = minX; var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink;
}
var minY = nn.h/2 -5;
if (nn.y < minY) {
nn.y = minY;
}
var maxX = space_width -nn.w/2 +5;
if (nn.x > maxX) {
nn.x = maxX;
}
var maxY = space_height -nn.h +5;
if (nn.y > maxY) {
nn.y = maxY;
}
if (snapGrid) { var label = RED.utils.getNodeLabel(nn, nn.type);
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn); var labelParts = getLabelParts(label, "red-ui-flow-node-label");
nn.x -= gridOffset.x; if (hideLabel) {
nn.y -= gridOffset.y; nn.w = node_height;
} nn.h = Math.max(node_height,(nn.outputs || 0) * 15);
} else {
nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) );
nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30);
}
} catch(err) {
}
var linkToSplice = $(ui.helper).data("splice"); mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]);
if (linkToSplice) { mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]);
spliceLink(linkToSplice, nn, historyEvent) mousePos[1] /= scaleFactor;
} mousePos[0] /= scaleFactor;
nn.x = mousePos[0];
nn.y = mousePos[1];
var minX = nn.w/2 -5;
if (nn.x < minX) {
nn.x = minX;
}
var minY = nn.h/2 -5;
if (nn.y < minY) {
nn.y = minY;
}
var maxX = space_width -nn.w/2 +5;
if (nn.x > maxX) {
nn.x = maxX;
}
var maxY = space_height -nn.h +5;
if (nn.y > maxY) {
nn.y = maxY;
}
if (snapGrid) {
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn);
nn.x -= gridOffset.x;
nn.y -= gridOffset.y;
}
var linkToSplice = $(ui.helper).data("splice");
if (linkToSplice) {
spliceLink(linkToSplice, nn, historyEvent)
}
var group = $(ui.helper).data("group");
if (group) {
var oldX = group.x;
var oldY = group.y;
RED.group.addToGroup(group, nn);
var moveEvent = null;
if ((group.x !== oldX) ||
(group.y !== oldY)) {
moveEvent = {
t: "move",
nodes: [{n: group,
ox: oldX, oy: oldY,
dx: group.x -oldX,
dy: group.y -oldY}],
dirty: true
};
}
historyEvent = {
t: 'multi',
events: [historyEvent],
var group = $(ui.helper).data("group");
if (group) {
var oldX = group.x;
var oldY = group.y;
RED.group.addToGroup(group, nn);
var moveEvent = null;
if ((group.x !== oldX) ||
(group.y !== oldY)) {
moveEvent = {
t: "move",
nodes: [{n: group,
ox: oldX, oy: oldY,
dx: group.x -oldX,
dy: group.y -oldY}],
dirty: true
}; };
if (moveEvent) {
historyEvent.events.push(moveEvent)
}
historyEvent.events.push({
t: "addToGroup",
group: group,
nodes: nn
})
} }
historyEvent = {
t: 'multi',
events: [historyEvent],
}; RED.history.push(historyEvent);
if (moveEvent) { RED.editor.validateNode(nn);
historyEvent.events.push(moveEvent) RED.nodes.dirty(true);
// auto select dropped node - so info shows (if visible)
clearSelection();
nn.selected = true;
movingSet.add(nn);
updateActiveNodes();
updateSelection();
redraw();
if (nn._def.autoedit) {
RED.editor.edit(nn);
}
} catch (error) {
if (error.code != "NODE_RED") {
RED.notify(RED._("notification.error",{message:error.toString()}),"error");
} else {
RED.notify(RED._("notification.error",{message:error.message}),"error");
} }
historyEvent.events.push({
t: "addToGroup",
group: group,
nodes: nn
})
}
RED.history.push(historyEvent);
RED.editor.validateNode(nn);
RED.nodes.dirty(true);
// auto select dropped node - so info shows (if visible)
clearSelection();
nn.selected = true;
movingSet.add(nn);
updateActiveNodes();
updateSelection();
redraw();
if (nn._def.autoedit) {
RED.editor.edit(nn);
} }
} }
}); });
@@ -6063,14 +6071,19 @@ RED.view = (function() {
function createNode(type, x, y, z) { function createNode(type, x, y, z) {
const wasDirty = RED.nodes.dirty() const wasDirty = RED.nodes.dirty()
var m = /^subflow:(.+)$/.exec(type); var m = /^subflow:(.+)$/.exec(type);
var activeSubflow = z ? RED.nodes.subflow(z) : null; var activeSubflow = (z || RED.workspaces.active()) ? RED.nodes.subflow(z || RED.workspaces.active()) : null;
if (activeSubflow && m) { if (activeSubflow && m) {
var subflowId = m[1]; var subflowId = m[1];
let err
if (subflowId === activeSubflow.id) { if (subflowId === activeSubflow.id) {
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddSubflowToItself") })) err = new Error(RED._("notification.errors.cannotAddSubflowToItself"))
} else if (RED.nodes.subflowContains(m[1], activeSubflow.id)) {
err = new Error(RED._("notification.errors.cannotAddCircularReference"))
} }
if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { if (err) {
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddCircularReference") })) err.code = 'NODE_RED'
throw err
} }
} }

View File

@@ -491,6 +491,11 @@ RED.workspaces = (function() {
createWorkspaceTabs(); createWorkspaceTabs();
RED.events.on("sidebar:resize",workspace_tabs.resize); RED.events.on("sidebar:resize",workspace_tabs.resize);
RED.events.on("workspace:clear", () => {
// Reset the index used to generate new flow names
workspaceIndex = 0
})
RED.actions.add("core:show-next-tab",function() { RED.actions.add("core:show-next-tab",function() {
var oldActive = activeWorkspace; var oldActive = activeWorkspace;
workspace_tabs.nextTab(); workspace_tabs.nextTab();
@@ -657,6 +662,9 @@ RED.workspaces = (function() {
RED.events.on("flows:change", (ws) => { RED.events.on("flows:change", (ws) => {
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); $("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
}) })
RED.events.on("subflows:change", (ws) => {
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
})
hideWorkspace(); hideWorkspace();
} }

View File

@@ -378,7 +378,7 @@
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
} else { } else {
const instanceNode = RED.nodes.node(id) const instanceNode = RED.nodes.node(id)
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name) const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8))?.name || instanceNode.type)
return { id: id, label: pathLabel } return { id: id, label: pathLabel }
} }
}) })

View File

@@ -194,27 +194,46 @@
nodeMap[node.links[i]].new = true; nodeMap[node.links[i]].new = true;
} }
} }
var n;
for (var id in nodeMap) { let editHistories = []
let n;
for (let id in nodeMap) {
if (nodeMap.hasOwnProperty(id)) { if (nodeMap.hasOwnProperty(id)) {
n = RED.nodes.node(id); n = RED.nodes.node(id);
if (n) { if (n) {
editHistories.push({
t:'edit',
node: n,
changes: {
links: [...n.links]
},
changed: n.changed
})
if (nodeMap[id].old && !nodeMap[id].new) { if (nodeMap[id].old && !nodeMap[id].new) {
// Removed id // Removed id
i = n.links.indexOf(node.id); i = n.links.indexOf(node.id);
if (i > -1) { if (i > -1) {
n.links.splice(i,1); n.links.splice(i,1);
n.changed = true
n.dirty = true
} }
} else if (!nodeMap[id].old && nodeMap[id].new) { } else if (!nodeMap[id].old && nodeMap[id].new) {
// Added id // Added id
i = n.links.indexOf(id); i = n.links.indexOf(id);
if (i === -1) { if (i === -1) {
n.links.push(node.id); n.links.push(node.id);
n.changed = true
n.dirty = true
} }
} }
} }
} }
} }
if (editHistories.length > 0) {
return {
history: editHistories
}
}
} }
function onAdd() { function onAdd() {
@@ -254,13 +273,14 @@
onEditPrepare(this,"link out"); onEditPrepare(this,"link out");
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); const result = onEditSave(this);
// In case the name has changed, ensure any link call nodes on this // In case the name has changed, ensure any link call nodes on this
// tab are redrawn with the updated name // tab are redrawn with the updated name
var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"}); var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"});
localCallNodes.forEach(function(node) { localCallNodes.forEach(function(node) {
node.dirty = true; node.dirty = true;
}); });
return result
}, },
onadd: onAdd, onadd: onAdd,
oneditresize: resizeNodeList oneditresize: resizeNodeList
@@ -329,7 +349,7 @@
onEditPrepare(this,"link in"); onEditPrepare(this,"link in");
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); return onEditSave(this);
}, },
oneditresize: resizeNodeList oneditresize: resizeNodeList
}); });
@@ -373,7 +393,7 @@
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); return onEditSave(this);
}, },
onadd: onAdd, onadd: onAdd,
oneditresize: resizeNodeList oneditresize: resizeNodeList

View File

@@ -374,7 +374,7 @@ module.exports = function(RED) {
iniOpt.breakOnSigint = true; iniOpt.breakOnSigint = true;
} }
} }
node.script = vm.createScript(functionText, createVMOpt(node, "")); node.script = new vm.Script(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) { if (node.fin && (node.fin !== "")) {
var finText = `(function () { var finText = `(function () {
var node = { var node = {
@@ -438,10 +438,9 @@ module.exports = function(RED) {
//store the error in msg to be used in flows //store the error in msg to be used in flows
msg.error = err; msg.error = err;
var line = 0;
var errorMessage;
if (stack.length > 0) { if (stack.length > 0) {
let line = 0;
let errorMessage;
while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) { while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) {
line++; line++;
} }
@@ -455,11 +454,13 @@ module.exports = function(RED) {
errorMessage += " (line "+lineno+", col "+cha+")"; errorMessage += " (line "+lineno+", col "+cha+")";
} }
} }
if (errorMessage) {
err.message = errorMessage
}
} }
if (!errorMessage) { // Pass the whole error object so any additional properties
errorMessage = err.toString(); // (such as cause) are preserved
} done(err);
done(errorMessage);
} }
else if (typeof err === "string") { else if (typeof err === "string") {
done(err); done(err);

View File

@@ -20,6 +20,7 @@ module.exports = function(RED) {
var exec = require('child_process').exec; var exec = require('child_process').exec;
var fs = require('fs'); var fs = require('fs');
var isUtf8 = require('is-utf8'); var isUtf8 = require('is-utf8');
const isWindows = process.platform === 'win32'
function ExecNode(n) { function ExecNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@@ -85,9 +86,12 @@ module.exports = function(RED) {
} }
}); });
var cmd = arg.shift(); var cmd = arg.shift();
// Since 18.20.2/20.12.2, it is invalid to call spawn on Windows with a .bat/.cmd file
// without using shell: true.
const opts = isWindows ? { ...node.spawnOpt, shell: true } : node.spawnOpt
/* istanbul ignore else */ /* istanbul ignore else */
node.debug(cmd+" ["+arg+"]"); node.debug(cmd+" ["+arg+"]");
child = spawn(cmd,arg,node.spawnOpt); child = spawn(cmd,arg,opts);
node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid}); node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid});
var unknownCommand = (child.pid === undefined); var unknownCommand = (child.pid === undefined);
if (node.timer !== 0) { if (node.timer !== 0) {

View File

@@ -103,7 +103,7 @@
<h4>Automatic mode</h4> <h4>Automatic mode</h4>
<p>Automatic mode uses the <code>parts</code> property of incoming messages to <p>Automatic mode uses the <code>parts</code> property of incoming messages to
determine how the sequence should be joined. This allows it to automatically determine how the sequence should be joined. This allows it to automatically
reverse the action of a <b>split</b> node. reverse the action of a <b>split</b> node.</p>
<h4>Manual mode</h4> <h4>Manual mode</h4>
<p>When configured to join in manual mode, the node is able to join sequences <p>When configured to join in manual mode, the node is able to join sequences

View File

@@ -1,3 +1,3 @@
<script type="text/html" data-help-name="global-config"> <script type="text/html" data-help-name="global-config">
<p>大域的なフローの設定を保持するノード大域的な環境変数の定義を含みます</p> <p>大域的なフローの設定を保持するノード大域的な環境変数の定義を含みます</p>
</script>p </script>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/nodes", "name": "@node-red/nodes",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -273,7 +273,7 @@ async function installModule(moduleDetails) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['install', ...extraArgs, installSpec] let args = ['install', ...extraArgs, installSpec]
log.trace(NPM_COMMAND + JSON.stringify(args)); log.trace(NPM_COMMAND + JSON.stringify(args));
return exec.run(NPM_COMMAND, args, { cwd: installDir },true) return exec.run(NPM_COMMAND, args, { cwd: installDir, shell: true },true)
} else { } else {
log.trace("skipping npm install"); log.trace("skipping npm install");
} }

View File

@@ -25,12 +25,15 @@ const registryUtil = require("./util");
const library = require("./library"); const library = require("./library");
const {exec,log,events,hooks} = require("@node-red/util"); const {exec,log,events,hooks} = require("@node-red/util");
const child_process = require('child_process'); const child_process = require('child_process');
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
let installerEnabled = false;
const isWindows = process.platform === 'win32'
const npmCommand = isWindows ? 'npm.cmd' : 'npm';
let installerEnabled = false;
let settings; let settings;
const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/; const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/;
const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/; const slashRe = isWindows ? /\\|[/]/ : /[/]/;
const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/;
@@ -225,7 +228,7 @@ async function installModule(module,version,url) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['install', ...extraArgs, installName] let args = ['install', ...extraArgs, installName]
log.trace(npmCommand + JSON.stringify(args)); log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true) return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true)
} else { } else {
log.trace("skipping npm install"); log.trace("skipping npm install");
} }
@@ -260,7 +263,7 @@ async function installModule(module,version,url) {
log.warn("------------------------------------------"); log.warn("------------------------------------------");
e = new Error(log._("server.install.install-failed")+": "+err.toString()); e = new Error(log._("server.install.install-failed")+": "+err.toString());
if (err.hook === "postInstall") { if (err.hook === "postInstall") {
return exec.run(npmCommand,["remove",module],{ cwd: installDir}, false).finally(() => { return exec.run(npmCommand,["remove",module],{ cwd: installDir, shell: true }, false).finally(() => {
throw e; throw e;
}) })
} }
@@ -356,7 +359,7 @@ async function getModuleVersionFromNPM(module, version) {
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
child_process.execFile(npmCommand,['info','--json',installName],function(err,stdout,stderr) { child_process.execFile(npmCommand,['info','--json',installName],{ shell: true },function(err,stdout,stderr) {
try { try {
if (!stdout) { if (!stdout) {
log.warn(log._("server.install.install-failed-not-found",{name:module})); log.warn(log._("server.install.install-failed-not-found",{name:module}));
@@ -511,7 +514,7 @@ function uninstallModule(module) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['remove', ...extraArgs, module] let args = ['remove', ...extraArgs, module]
log.trace(npmCommand + JSON.stringify(args)); log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true) return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true)
} else { } else {
log.trace("skipping npm uninstall"); log.trace("skipping npm uninstall");
} }
@@ -578,7 +581,7 @@ async function checkPrereq() {
installerEnabled = false; installerEnabled = false;
} else { } else {
return new Promise(resolve => { return new Promise(resolve => {
child_process.execFile(npmCommand,['-v'],function(err,stdout) { child_process.execFile(npmCommand,['-v'],{ shell: true },function(err,stdout) {
if (err) { if (err) {
log.info(log._("server.palette-editor.npm-not-found")); log.info(log._("server.palette-editor.npm-not-found"));
installerEnabled = false; installerEnabled = false;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/registry", "name": "@node-red/registry",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,11 +16,11 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "3.1.7", "@node-red/util": "3.1.9",
"clone": "2.1.2", "clone": "2.1.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"semver": "7.5.4", "semver": "7.5.4",
"tar": "6.1.13", "tar": "6.2.1",
"uglify-js": "3.17.4" "uglify-js": "3.17.4"
} }
} }

View File

@@ -678,6 +678,9 @@ class Flow {
if (logMessage.hasOwnProperty('stack')) { if (logMessage.hasOwnProperty('stack')) {
errorMessage.error.stack = logMessage.stack; errorMessage.error.stack = logMessage.stack;
} }
if (logMessage.hasOwnProperty('cause')) {
errorMessage.error.cause = logMessage.cause;
}
targetCatchNode.receive(errorMessage); targetCatchNode.receive(errorMessage);
handled = true; handled = true;
}); });

View File

@@ -106,14 +106,22 @@ async function evaluateEnvProperties(flow, env, credentials) {
result = { value: result, __clone__: true} result = { value: result, __clone__: true}
} }
evaluatedEnv[name] = result evaluatedEnv[name] = result
} else {
evaluatedEnv[name] = undefined
flow.error(`Error evaluating env property '${name}': ${err.toString()}`)
} }
resolve() resolve()
}); });
})) }))
} else { } else {
value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null); try {
if (typeof value === 'object') { value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null);
value = { value: value, __clone__: true} if (typeof value === 'object') {
value = { value: value, __clone__: true}
}
} catch (err) {
value = undefined
flow.error(`Error evaluating env property '${name}': ${err.toString()}`)
} }
} }
evaluatedEnv[name] = value evaluatedEnv[name] = value

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/runtime", "name": "@node-red/runtime",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,11 +16,11 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/registry": "3.1.7", "@node-red/registry": "3.1.9",
"@node-red/util": "3.1.7", "@node-red/util": "3.1.9",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"clone": "2.1.2", "clone": "2.1.2",
"express": "4.18.2", "express": "4.19.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"json-stringify-safe": "5.0.1" "json-stringify-safe": "5.0.1"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/util", "name": "@node-red/util",
"version": "3.1.7", "version": "3.1.9",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "3.1.7", "version": "3.1.9",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org", "homepage": "https://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -31,15 +31,15 @@
"flow" "flow"
], ],
"dependencies": { "dependencies": {
"@node-red/editor-api": "3.1.7", "@node-red/editor-api": "3.1.9",
"@node-red/runtime": "3.1.7", "@node-red/runtime": "3.1.9",
"@node-red/util": "3.1.7", "@node-red/util": "3.1.9",
"@node-red/nodes": "3.1.7", "@node-red/nodes": "3.1.9",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"express": "4.18.2", "express": "4.19.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"node-red-admin": "^3.1.2", "node-red-admin": "^3.1.3",
"nopt": "5.0.0", "nopt": "5.0.0",
"semver": "7.5.4" "semver": "7.5.4"
}, },

View File

@@ -390,7 +390,8 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR); msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', 'n1'); msg.should.have.property('id', 'n1');
msg.should.have.property('type', 'function'); msg.should.have.property('type', 'function');
msg.should.have.property('msg', 'ReferenceError: retunr is not defined (line 2, col 1)'); msg.should.have.property('msg')
msg.msg.message.should.equal('ReferenceError: retunr is not defined (line 2, col 1)');
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);
@@ -659,7 +660,8 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR); msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', name); msg.should.have.property('id', name);
msg.should.have.property('type', 'function'); msg.should.have.property('type', 'function');
msg.should.have.property('msg', 'Error: Callback must be a function'); msg.should.have.property('msg')
msg.msg.message.should.equal('Callback must be a function');
done(); done();
} }
catch (e) { catch (e) {

View File

@@ -60,6 +60,7 @@ describe('HTTP Request Node', function() {
function startServer(done) { function startServer(done) {
testPort += 1; testPort += 1;
testServer = stoppable(http.createServer(testApp)); testServer = stoppable(http.createServer(testApp));
const promises = []
testServer.listen(testPort,function(err) { testServer.listen(testPort,function(err) {
testSslPort += 1; testSslPort += 1;
console.log("ssl port", testSslPort); console.log("ssl port", testSslPort);
@@ -81,13 +82,17 @@ describe('HTTP Request Node', function() {
*/ */
}; };
testSslServer = stoppable(https.createServer(sslOptions,testApp)); testSslServer = stoppable(https.createServer(sslOptions,testApp));
testSslServer.listen(testSslPort, function(err){ console.log('> start testSslServer')
if (err) { promises.push(new Promise((resolve, reject) => {
console.log(err); testSslServer.listen(testSslPort, function(err){
} else { console.log(' done testSslServer')
console.log("started testSslServer"); if (err) {
} reject(err)
}); } else {
resolve()
}
});
}))
testSslClientPort += 1; testSslClientPort += 1;
var sslClientOptions = { var sslClientOptions = {
@@ -97,10 +102,17 @@ describe('HTTP Request Node', function() {
requestCert: true requestCert: true
}; };
testSslClientServer = stoppable(https.createServer(sslClientOptions, testApp)); testSslClientServer = stoppable(https.createServer(sslClientOptions, testApp));
testSslClientServer.listen(testSslClientPort, function(err){ console.log('> start testSslClientServer')
console.log("ssl-client", err) promises.push(new Promise((resolve, reject) => {
}); testSslClientServer.listen(testSslClientPort, function(err){
console.log(' done testSslClientServer')
if (err) {
reject(err)
} else {
resolve()
}
});
}))
testProxyPort += 1; testProxyPort += 1;
testProxyServer = stoppable(httpProxy(http.createServer())) testProxyServer = stoppable(httpProxy(http.createServer()))
@@ -109,7 +121,17 @@ describe('HTTP Request Node', function() {
res.setHeader("x-testproxy-header", "foobar") res.setHeader("x-testproxy-header", "foobar")
} }
}) })
testProxyServer.listen(testProxyPort) console.log('> testProxyServer')
promises.push(new Promise((resolve, reject) => {
testProxyServer.listen(testProxyPort, function(err) {
console.log(' done testProxyServer')
if (err) {
reject(err)
} else {
resolve()
}
})
}))
testProxyAuthPort += 1 testProxyAuthPort += 1
testProxyServerAuth = stoppable(httpProxy(http.createServer())) testProxyServerAuth = stoppable(httpProxy(http.createServer()))
@@ -131,9 +153,19 @@ describe('HTTP Request Node', function() {
res.setHeader("x-testproxy-header", "foobar") res.setHeader("x-testproxy-header", "foobar")
} }
}) })
testProxyServerAuth.listen(testProxyAuthPort) console.log('> testProxyServerAuth')
promises.push(new Promise((resolve, reject) => {
testProxyServerAuth.listen(testProxyAuthPort, function(err) {
console.log(' done testProxyServerAuth')
if (err) {
reject(err)
} else {
resolve()
}
})
}))
done(err); Promise.all(promises).then(() => { done() }).catch(done)
}); });
} }
@@ -429,7 +461,11 @@ describe('HTTP Request Node', function() {
if (err) { if (err) {
done(err); done(err);
} }
helper.startServer(done); console.log('> helper.startServer')
helper.startServer(function(err) {
console.log('> helper started')
done(err)
});
}); });
}); });