mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'dev' into debug-node-with-jsonata
This commit is contained in:
commit
987dbf8a92
94
CHANGELOG.md
94
CHANGELOG.md
@ -1,3 +1,97 @@
|
||||
#### 0.20.0-beta.2: Beta Release
|
||||
|
||||
- Split Node-RED internals into multiple sub-modules
|
||||
|
||||
Editor
|
||||
|
||||
- Allow the editor to use a custom admin api url root
|
||||
- Improve performance of Flow Diff dialog - @TothiViseo #1989
|
||||
- Add 'open project' option to Projects Welcome dialog
|
||||
- Add 'type already registered' check in palette editor
|
||||
- Handle missing tab.disabled property
|
||||
- Handle missing wires prop and string x/y props on import
|
||||
- Add RED.notifications.hide flag - for UI testing
|
||||
- Improve alignment of node label edit inputs
|
||||
- Show arrow-in node when invalid font-awesome icon name was specified for default icon
|
||||
- Add ability to delete context values from sidebar
|
||||
- Allow copy-to-clipboard copy whole tabs
|
||||
- Make disabled flows more obvious in editor
|
||||
- Allow import/export from file in editor
|
||||
- Allow config nodes to be selected in sidebar and deleted
|
||||
- Show port label of subflow with input port
|
||||
- Support ctrl-click selection of flow tabs
|
||||
- Allow left-hand node button to act as toggle
|
||||
- Support dbl-click in tab bar to add new flow in position
|
||||
- Fix duplicate subflow detection on import
|
||||
- Add import notification with info on what has been imported Closes #1862
|
||||
- Show error details when trying to import invalid json
|
||||
- Show default icon when non-existent font-awesome icon was specified
|
||||
- Add configurable option for showing node label
|
||||
- Avoid http redirects as Safari doesn't reuse Auth header Fixes #1903
|
||||
- Tidy up ace tooltip styling
|
||||
- Add event log to editor
|
||||
- Add tooltips to multiple editor elements
|
||||
- Allow palette to be hidden
|
||||
- Add node module into to sidebar and palette popover
|
||||
- Mark all newly imported nodes as changed
|
||||
- Allow a node label to be hidden
|
||||
- Add markdown formatting toolbar
|
||||
- Add markdown toolbar to various editors
|
||||
- Fix i18n handling for ja-JP locale on Safari/MacOS
|
||||
- Add node body tooltip
|
||||
- Decrease opacity of flow-navigator
|
||||
- Update tooltip style
|
||||
- Update ACE to 1.4.1-src-min-noconflict
|
||||
- Cache node locales by language
|
||||
- Show icon element with either icon image or fa-icon
|
||||
- Added font-awesome icons to user defined icon
|
||||
- Update info side bar with node description section
|
||||
- One-click search of config node users
|
||||
- Redesign node edit dialog to tabbed style
|
||||
- Add 'restart flows' option to deploy menu
|
||||
- Add node description property UI
|
||||
|
||||
|
||||
Runtime
|
||||
|
||||
- Allow a project to be loaded from cmdline
|
||||
- Handle lookup of undefined property in Global context Fixes #1978
|
||||
- Refuse to enable Manage Palette if npm too old
|
||||
- Remove restriction on upgrading non-local modules
|
||||
- Remove deprecated Buffer constructor usage Fixes #1709
|
||||
- Update httpServerOptions doc in settings.js
|
||||
- Exclude non-testable .js files from the unit tests
|
||||
- Add --safe mode flag to allow starting without flows running
|
||||
- Add setting-defined accessToken for automated access to the adminAPI - #1789
|
||||
|
||||
Nodes
|
||||
|
||||
- Move all core node EN help to their own locale files - #1990
|
||||
- CSV: better regex for number detection
|
||||
- Debug: hide button if not configured to send to sidebar
|
||||
- Delay: report queue activity when in by-topic mode
|
||||
- Delay: add msg.flush mode
|
||||
- Exec: Preserve existing properties on msg object
|
||||
- File: remove CR/LF from incoming filename
|
||||
- Function: create custom ace javascript mode to handle ES6 Fixes #1911
|
||||
- Function: add env.get
|
||||
- HTTP Request: Add http-proxy config #1913
|
||||
- HTTP Request: add msg.redirectList to output
|
||||
- HTTP Request: add msg.requestTimeout option for per-message setting - @natcl #1959
|
||||
- MQTT: add auto-detect and base64 output to mqtt node Fixes #1912 - @DurandA
|
||||
- MQTT: only unsubscribe node that is being removed
|
||||
- Sentiment: move to node-red-node-sentiment
|
||||
- Switch: add missing edit dialog icon
|
||||
- Tail: move to node-red-node-tail
|
||||
- TCPGet: clear status if user changes target per message
|
||||
- Template: tidy up edit dialog
|
||||
- UDP: more resilient binding to correct port for udp, give input side priority
|
||||
- Split/Join: add msg.reset to info panel
|
||||
- Split/Join: reset join without sending part array
|
||||
- Watch: add msg.filename so can feed direct to file in node
|
||||
- WebSocket: preserve \_session on msg but don't send as part of wholemsg
|
||||
|
||||
|
||||
#### 0.19.5: Maintenance Release
|
||||
|
||||
- Recognize pip installs of RPi.GPIO (#1934)
|
||||
|
27
Gruntfile.js
27
Gruntfile.js
@ -373,6 +373,10 @@ module.exports = function(grunt) {
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'packages/node_modules/@node-red/editor-client/public/red/about'
|
||||
},
|
||||
{
|
||||
src: 'CHANGELOG.md',
|
||||
dest: 'packages/node_modules/node-red/'
|
||||
},
|
||||
{
|
||||
cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/',
|
||||
src: '**',
|
||||
@ -429,23 +433,18 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
jsdoc : {
|
||||
runtimeAPI: {
|
||||
modules: {
|
||||
src: [
|
||||
'packages/node_modules/node-red/lib/red.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js',
|
||||
'packages/node_modules/@node-red/util/**/*.js',
|
||||
],
|
||||
options: {
|
||||
destination: 'docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
},
|
||||
nodeREDUtil: {
|
||||
src: 'packages/node_modules/@node-red/util/**/*.js',
|
||||
options: {
|
||||
destination: 'packages/node_modules/@node-red/util/docs',
|
||||
configure: './jsdoc.json'
|
||||
}
|
||||
}
|
||||
},
|
||||
jsdoc2md: {
|
||||
@ -453,8 +452,11 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
separators: true
|
||||
},
|
||||
src: ['packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js'],
|
||||
src: [
|
||||
'packages/node_modules/@node-red/runtime/lib/index.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/api/*.js',
|
||||
'packages/node_modules/@node-red/runtime/lib/events.js'
|
||||
],
|
||||
dest: 'packages/node_modules/@node-red/runtime/docs/api.md'
|
||||
},
|
||||
nodeREDUtil: {
|
||||
@ -528,12 +530,15 @@ module.exports = function(grunt) {
|
||||
});
|
||||
|
||||
grunt.registerTask('verifyPackageDependencies', function() {
|
||||
var done = this.async();
|
||||
var verifyDependencies = require("./scripts/verify-package-dependencies.js");
|
||||
var failures = verifyDependencies();
|
||||
verifyDependencies().then(function(failures) {
|
||||
if (failures.length > 0) {
|
||||
failures.forEach(f => grunt.log.error(f));
|
||||
grunt.fail.fatal("Failed to verify package dependencies");
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('setDevEnv',
|
||||
|
36
package.json
36
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@ -24,7 +24,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.5.4",
|
||||
"ajv": "6.6.1",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
@ -32,29 +32,31 @@
|
||||
"clone": "2.1.2",
|
||||
"cookie": "0.3.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.5.0",
|
||||
"denque": "1.3.0",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.5.1",
|
||||
"denque": "1.4.0",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"i18next": "11.6.0",
|
||||
"i18next": "12.1.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.4",
|
||||
"media-typer": "0.3.0",
|
||||
"media-typer": "1.0.1",
|
||||
"memorystore": "1.6.0",
|
||||
"mime": "1.4.1",
|
||||
"mime": "2.4.0",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "2.3.2",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "^0.1.12",
|
||||
"mustache": "3.0.1",
|
||||
"node-red-node-email": "1.0.*",
|
||||
"node-red-node-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
"node-red-node-tail": "^0.0.1",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
@ -78,7 +80,7 @@
|
||||
"chromedriver": "2.43.1",
|
||||
"grunt": "~1.0.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.3.1",
|
||||
"grunt-cli": "~1.3.2",
|
||||
"grunt-concurrent": "~2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-compress": "~1.4.0",
|
||||
@ -104,12 +106,12 @@
|
||||
"mosca": "^2.8.3",
|
||||
"should": "^8.4.0",
|
||||
"sinon": "1.17.7",
|
||||
"stoppable": "^1.0.7",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "3.3.0",
|
||||
"wdio-chromedriver-service": "^0.1.3",
|
||||
"wdio-mocha-framework": "^0.6.2",
|
||||
"wdio-chromedriver-service": "^0.1.5",
|
||||
"wdio-mocha-framework": "^0.6.4",
|
||||
"wdio-spec-reporter": "^0.1.5",
|
||||
"webdriverio": "^4.13.1",
|
||||
"webdriverio": "^4.14.1",
|
||||
"node-red-node-test-helper": "node-red/node-red-node-test-helper",
|
||||
"jsdoc-nr-template": "node-red/jsdoc-nr-template"
|
||||
},
|
||||
|
@ -57,7 +57,7 @@ module.exports = {
|
||||
}
|
||||
runtimeAPI.nodes.getIcon(opts).then(function(data) {
|
||||
if (data) {
|
||||
var contentType = mime.lookup(icon);
|
||||
var contentType = mime.getType(icon);
|
||||
res.set("Content-Type", contentType);
|
||||
res.send(data);
|
||||
} else {
|
||||
|
@ -100,5 +100,5 @@ module.exports = {
|
||||
auth: {
|
||||
needsPermission: auth.needsPermission
|
||||
},
|
||||
get adminApp() { return adminApp; }
|
||||
get httpAdmin() { return adminApp; }
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -8,21 +8,25 @@
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "*",
|
||||
"@node-red/editor-client": "*",
|
||||
"@node-red/util": "0.20.0-beta.2",
|
||||
"@node-red/editor-client": "0.20.0-beta.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.18.3",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.4",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.15.6",
|
||||
"express": "4.16.4",
|
||||
"memorystore": "1.6.0",
|
||||
"mime": "1.4.1",
|
||||
"mustache": "2.3.2",
|
||||
"mime": "2.4.0",
|
||||
"mustache": "3.0.1",
|
||||
"oauth2orize": "1.11.0",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
|
@ -1,14 +1,18 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"main": "./lib/index.js"
|
||||
}
|
||||
|
@ -865,7 +865,7 @@ RED.editor = (function() {
|
||||
var inputPlaceholder = node._def.inputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
var outputPlaceholder = node._def.outputLabels?RED._("editor.defaultLabel"):RED._("editor.noDefaultLabel");
|
||||
|
||||
$('<div class="form-row"><span style="margin-left: 10px;" data-i18n="editor.labelInputs"></span><div id="node-label-form-inputs"></div></div>').appendTo(dialogForm);
|
||||
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelInputs"></span><div id="node-label-form-inputs"></div></div>').appendTo(dialogForm);
|
||||
var inputsDiv = $("#node-label-form-inputs");
|
||||
if (inputCount > 0) {
|
||||
for (i=0;i<inputCount;i++) {
|
||||
@ -874,7 +874,7 @@ RED.editor = (function() {
|
||||
} else {
|
||||
buildLabelRow().appendTo(inputsDiv);
|
||||
}
|
||||
$('<div class="form-row"><span style="margin-left: 10px;" data-i18n="editor.labelOutputs"></span><div id="node-label-form-outputs"></div></div>').appendTo(dialogForm);
|
||||
$('<div class="form-row"><span style="margin-left: 50px;" data-i18n="editor.labelOutputs"></span><div id="node-label-form-outputs"></div></div>').appendTo(dialogForm);
|
||||
var outputsDiv = $("#node-label-form-outputs");
|
||||
if (outputCount > 0) {
|
||||
for (i=0;i<outputCount;i++) {
|
||||
|
@ -16,6 +16,10 @@
|
||||
RED.notifications = (function() {
|
||||
|
||||
/*
|
||||
If RED.notifications.hide is set to true, all notifications will be hidden.
|
||||
This is to help with UI testing in certain cases and not intended for the
|
||||
end-user.
|
||||
|
||||
// Example usage for a modal dialog with buttons
|
||||
var myNotification = RED.notify("This is the message to display",{
|
||||
modal: true,
|
||||
@ -108,7 +112,9 @@ RED.notifications = (function() {
|
||||
|
||||
|
||||
$("#notifications").append(n);
|
||||
if (!RED.notifications.hide) {
|
||||
$(n).slideDown(300);
|
||||
}
|
||||
n.close = (function() {
|
||||
var nn = n;
|
||||
return function() {
|
||||
@ -123,9 +129,13 @@ RED.notifications = (function() {
|
||||
notificationButtonWrapper.hide();
|
||||
}
|
||||
}
|
||||
if (!RED.notifications.hide) {
|
||||
$(nn).slideUp(300, function() {
|
||||
nn.parentNode.removeChild(nn);
|
||||
});
|
||||
} else {
|
||||
nn.parentNode.removeChild(nn);
|
||||
}
|
||||
if (options.modal) {
|
||||
$("#full-shade").hide();
|
||||
}
|
||||
@ -138,8 +148,10 @@ RED.notifications = (function() {
|
||||
return
|
||||
}
|
||||
nn.hidden = true;
|
||||
if (!RED.notifications.hide) {
|
||||
$(nn).slideUp(300);
|
||||
}
|
||||
}
|
||||
})();
|
||||
n.showNotification = (function() {
|
||||
var nn = n;
|
||||
@ -148,8 +160,10 @@ RED.notifications = (function() {
|
||||
return
|
||||
}
|
||||
nn.hidden = false;
|
||||
if (!RED.notifications.hide) {
|
||||
$(nn).slideDown(300);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
n.update = (function() {
|
||||
|
@ -789,7 +789,11 @@ RED.utils = (function() {
|
||||
return RED.settings.apiRootUrl+"icons/"+iconPath.module+"/"+iconPath.file;
|
||||
}
|
||||
} else {
|
||||
if (def.category === 'subflows') {
|
||||
// This could be a non-core node trying to use a core icon.
|
||||
iconPath.module = 'node-red';
|
||||
if (isIconExists(iconPath)) {
|
||||
return RED.settings.apiRootUrl+"icons/"+iconPath.module+"/"+iconPath.file;
|
||||
} else if (def.category === 'subflows') {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/subflow.png";
|
||||
} else {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/arrow-in.png";
|
||||
|
@ -343,7 +343,7 @@
|
||||
top: -3000px;
|
||||
}
|
||||
.node-label-form-row {
|
||||
margin: 5px 0;
|
||||
margin: 5px 0 0 50px;
|
||||
label {
|
||||
margin-right: 20px;
|
||||
text-align: right;
|
||||
|
@ -1,37 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="sentiment">
|
||||
<div class="form-row">
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width:70%;"/>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('sentiment',{
|
||||
category: 'analysis-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"sentiment";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if (this.property === undefined) {
|
||||
$("#node-input-property").val("payload");
|
||||
}
|
||||
$("#node-input-property").typedInput({default:'msg',types:['msg']});
|
||||
}
|
||||
});
|
||||
</script>
|
@ -1,23 +0,0 @@
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var sentiment = require('sentiment');
|
||||
|
||||
function SentimentNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.property = n.property||"payload";
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var value = RED.util.getMessageProperty(msg,node.property);
|
||||
if (value !== undefined) {
|
||||
sentiment(value, msg.overrides || null, function (err, result) {
|
||||
msg.sentiment = result;
|
||||
node.send(msg);
|
||||
});
|
||||
}
|
||||
else { node.send(msg); } // If no matching property - just pass it on.
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("sentiment",SentimentNode);
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
<script type="text/x-red" data-template-name="template">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-field"><i class="fa fa-edit"></i> <span data-i18n="template.label.property"></span></label>
|
||||
<label for="node-input-field"><i class="fa fa-ellipsis-h"></i> <span data-i18n="template.label.property"></span></label>
|
||||
<input type="text" id="node-input-field" placeholder="payload" style="width:250px;">
|
||||
<input type="hidden" id="node-input-fieldType">
|
||||
</div>
|
||||
|
@ -131,8 +131,16 @@ module.exports = function(RED) {
|
||||
if (msg.hasOwnProperty('followRedirects')) {
|
||||
opts.followRedirect = msg.followRedirects;
|
||||
}
|
||||
var redirectList = [];
|
||||
if (!opts.hasOwnProperty('followRedirect') || opts.followRedirect) {
|
||||
opts.followRedirect = function(res) {
|
||||
var redirectInfo = {
|
||||
location: res.headers.location,
|
||||
};
|
||||
if (res.headers.hasOwnProperty('set-cookie')) {
|
||||
redirectInfo.cookies = extractCookies(res.headers['set-cookie']);
|
||||
}
|
||||
redirectList.push(redirectInfo);
|
||||
if (this.headers.cookie) {
|
||||
delete this.headers.cookie;
|
||||
}
|
||||
@ -256,17 +264,10 @@ module.exports = function(RED) {
|
||||
msg.headers = res.headers;
|
||||
msg.responseUrl = res.request.uri.href;
|
||||
msg.payload = body;
|
||||
msg.redirectList = redirectList;
|
||||
|
||||
if (msg.headers.hasOwnProperty('set-cookie')) {
|
||||
msg.responseCookies = {};
|
||||
msg.headers['set-cookie'].forEach(function(c) {
|
||||
var parsedCookie = cookie.parse(c);
|
||||
var eq_idx = c.indexOf('=');
|
||||
var key = c.substr(0, eq_idx).trim()
|
||||
parsedCookie.value = parsedCookie[key];
|
||||
delete parsedCookie[key];
|
||||
msg.responseCookies[key] = parsedCookie;
|
||||
});
|
||||
msg.responseCookies = extractCookies(msg.headers['set-cookie']);
|
||||
}
|
||||
msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
|
||||
// msg.url = url; // revert when warning above finally removed
|
||||
@ -299,6 +300,19 @@ module.exports = function(RED) {
|
||||
this.on("close",function() {
|
||||
node.status({});
|
||||
});
|
||||
|
||||
function extractCookies(setCookie) {
|
||||
var cookies = {};
|
||||
setCookie.forEach(function(c) {
|
||||
var parsedCookie = cookie.parse(c);
|
||||
var eq_idx = c.indexOf('=');
|
||||
var key = c.substr(0, eq_idx).trim()
|
||||
parsedCookie.value = parsedCookie[key];
|
||||
delete parsedCookie[key];
|
||||
cookies[key] = parsedCookie;
|
||||
});
|
||||
return cookies;
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http request",HTTPRequest,{
|
||||
|
@ -20,7 +20,7 @@
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label data-i18n="switch.label.property"></label>
|
||||
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="switch.label.property"></span></label>
|
||||
<input type="text" id="node-input-property" style="width: 70%"/>
|
||||
<input type="hidden" id="node-input-outputs"/>
|
||||
</div>
|
||||
|
@ -1,51 +0,0 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="tail">
|
||||
<div class="form-row">
|
||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="tail.label.filename"></span></label>
|
||||
<input id="node-input-filename" type="text">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-filetype"><i class="fa fa-file-text-o"></i> <span data-i18n="tail.label.type"></span></label>
|
||||
<select type="text" id="node-input-filetype">
|
||||
<option value="text" data-i18n="tail.action.text"></option>
|
||||
<option value="binary" data-i18n="tail.action.binary"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="node-tail-split">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-split" style="width: 70%;"><span data-i18n="tail.label.splitlines"></span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tail',{
|
||||
category: 'storage-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filetype: {value:"text"},
|
||||
split: {value:false},
|
||||
filename: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "file.png",
|
||||
label: function() {
|
||||
return this.name||this.filename||this._("tail.tail");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-input-filetype").on("change",function() {
|
||||
if (this.value === "text") { $("#node-tail-split").show(); }
|
||||
else { $("#node-tail-split").hide(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
module.exports = function(RED) {
|
||||
"use strict";
|
||||
var spawn = require('child_process').spawn;
|
||||
var plat = require('os').platform();
|
||||
|
||||
if (plat.match(/^win/)) {
|
||||
throw RED._("tail.errors.windowsnotsupport");
|
||||
}
|
||||
|
||||
function TailNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.filetype = n.filetype || "text";
|
||||
this.split = n.split || false;
|
||||
var node = this;
|
||||
|
||||
var err = "";
|
||||
// TODO: rewrite to use node-tail
|
||||
var tail = spawn("tail", ["-F", "-n", "0", this.filename]);
|
||||
tail.stdout.on("data", function (data) {
|
||||
var msg = { topic:node.filename };
|
||||
if (node.filetype === "text") {
|
||||
if (node.split) {
|
||||
// TODO: allow customisation of the line break - as we do elsewhere
|
||||
var strings = data.toString().split("\n");
|
||||
for (var s in strings) {
|
||||
//TODO: should we really filter blanks? Is that expected?
|
||||
if (strings[s] !== "") {
|
||||
node.send({
|
||||
topic: node.filename,
|
||||
payload: strings[s]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data.toString();
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data;
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
tail.stderr.on("data", function(data) {
|
||||
node.error(data.toString());
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
/* istanbul ignore else */
|
||||
if (tail) { tail.kill(); }
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tail",TailNode);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>Analyses the chosen property, default <code>payload</code>, and adds a <code>sentiment</code> object.</p>
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">object</span></dt>
|
||||
<dd>contains the resulting AFINN-111 sentiment.</dd>
|
||||
<dt>sentiment.score <span class="property-type">number</span></dt>
|
||||
<dd>the sentiment score.</dd>
|
||||
</dl>
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">object</span></dt>
|
||||
<dd>an object of word score overrides can be supplied - <code>{ word:score,... }</code>.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>A score greater than zero is positive and less than zero is negative.</p>
|
||||
<p>The score typically ranges from -5 to +5, but can go higher and lower.</p>
|
||||
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>.</p>
|
||||
</script>
|
@ -53,6 +53,8 @@
|
||||
Otherwise, the url of the original request.</dd>
|
||||
<dt>responseCookies <span class="property-type">object</span></dt>
|
||||
<dd>If the response includes cookies, this propery is an object of name/value pairs for each cookie.</dd>
|
||||
<dt>redirectList <span class="property-type">array</span></dt>
|
||||
<dd>If the request was redirected one or more times, the accumulated information will be added to this property. `location` is the next redirect destination. `cookies` is the cookies returned from the redirect source.</dd>
|
||||
</dl>
|
||||
<h3>Details</h3>
|
||||
<p>When configured within the node, the URL property can contain <a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache-style</a> tags. These allow the
|
||||
|
@ -206,7 +206,7 @@
|
||||
"template": "template",
|
||||
"label": {
|
||||
"template": "Template",
|
||||
"property": "Set property",
|
||||
"property": "Property",
|
||||
"format": "Syntax Highlight",
|
||||
"syntax": "Format",
|
||||
"output": "Output as",
|
||||
@ -827,21 +827,6 @@
|
||||
"pythoncommandnotfound": "nrpgio python command not running"
|
||||
}
|
||||
},
|
||||
"tail": {
|
||||
"tail": "tail",
|
||||
"label": {
|
||||
"filename": "Filename",
|
||||
"type": "File type",
|
||||
"splitlines": "Split lines on \\n?"
|
||||
},
|
||||
"action": {
|
||||
"text": "Text - returns String",
|
||||
"binary": "Binary - returns Buffer"
|
||||
},
|
||||
"errors": {
|
||||
"windowsnotsupport": "Not currently supported on Windows."
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"label": {
|
||||
"filename": "Filename",
|
||||
|
@ -1,25 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="tail">
|
||||
<p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p>
|
||||
<p>This will not work on Windows filesystems, as it relies on the <b>tail -F</b> command.</p>
|
||||
<h3>Outputs</h3>
|
||||
<ul>
|
||||
<li>Text (UTF-8) files will be returned as strings.</li>
|
||||
<li>Binary files will be returned as Buffer objects.</li>
|
||||
</ul>
|
||||
</script>
|
@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>指定したプロパティ(デフォルトは<code>payload</code>)を分析し、<code>sentiment</code>オブジェクトを追加します。</p>
|
||||
<h3>出力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>sentiment <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>AFINN-111による感情分析の結果</dd>
|
||||
<dt>sentiment.score <span class="property-type">数値</span></dt>
|
||||
<dd>感情分析スコア</dd>
|
||||
</dl>
|
||||
<h3>入力</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>overrides <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>単語スコアの上書きをするためのオブジェクト - <code>{ word:score,... }</code></dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>ゼロ以上のスコアはポジティブ、ゼロ以下はネガティブを意味します。</p>
|
||||
<p>スコアの範囲は通常-5から+5ですが、より大きかったり小さかったりすることもあります。</p>
|
||||
<p>詳細は<a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_blank">the Sentiment docs here</a>を参照してください。</p>
|
||||
</script>
|
@ -46,6 +46,8 @@
|
||||
<dd>リクエストの処理時にリダイレクトが発生した場合、このプロパティが最後にリダイレクトされたURLを表します。リダイレクトが起こらなかった場合、最初リクエストのURLを表します。</dd>
|
||||
<dt>responseCookies <span class="property-type">オブジェクト</span></dt>
|
||||
<dd>レスポンスがクッキーを含む場合、このプロパティは各クッキーの名前/値を含むオブジェクトを表します。</dd>
|
||||
<dt>redirectList <span class="property-type">配列</span></dt>
|
||||
<dd>リクエストが一回以上リダイレクトされた場合は、このプロパティに情報が蓄積されます。`location`は、リダイレクト先を示します。`cookies`は、リダイレクト元から返されたクッキー情報です。</dd>
|
||||
</dl>
|
||||
<h3>詳細</h3>
|
||||
<p>ノードの設定でurlプロパティを指定する場合、<a href="http://mustache.github.io/mustache.5.html" target="_blank">mustache形式</a>のタグを含めることができます。これにより、URLを入力メッセージの値から構成することができます。例えば、urlが<code>example.com/{{{topic}}}</code>の場合、<code>msg.topic</code>の値による置き換えを自動的に行います。{{{...}}}表記を使うと、/、&といった文字をmustacheがエスケープするのを抑止できます。</p>
|
||||
|
@ -206,7 +206,7 @@
|
||||
"template": "template",
|
||||
"label": {
|
||||
"template": "テンプレート",
|
||||
"property": "設定先",
|
||||
"property": "プロパティ",
|
||||
"format": "構文",
|
||||
"syntax": "形式",
|
||||
"output": "出力形式",
|
||||
@ -825,21 +825,6 @@
|
||||
"pythoncommandnotfound": "nrpgio python コマンドが実行されていません"
|
||||
}
|
||||
},
|
||||
"tail": {
|
||||
"tail": "tail",
|
||||
"label": {
|
||||
"filename": "ファイル名",
|
||||
"type": "ファイル形式",
|
||||
"splitlines": "改行でメッセージを分割"
|
||||
},
|
||||
"action": {
|
||||
"text": "文字列",
|
||||
"binary": "バイナリバッファ"
|
||||
},
|
||||
"errors": {
|
||||
"windowsnotsupport": "現在Windows上での動作は対応していません"
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"label": {
|
||||
"filename": "ファイル名",
|
||||
|
@ -1,25 +0,0 @@
|
||||
<!--
|
||||
Copyright JS Foundation and other contributors, http://js.foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-help-name="tail">
|
||||
<p>設定したファイルの末尾を出力(追加されたデータを監視)します。(Linux/Macのみ)</p>
|
||||
<p>このノードは<b>tail -F</b>コマンドを内部で利用しているため、Windowsファイルシステムでは動作しません。</p>
|
||||
<h3>出力</h3>
|
||||
<ul>
|
||||
<li>(UTF-8形式の)テキストファイルは文字列を返却。</li>
|
||||
<li>バイナルファイルはバッファオブジェクトを返却。</li>
|
||||
</ul>
|
||||
</script>
|
@ -196,7 +196,7 @@
|
||||
"template": {
|
||||
"label": {
|
||||
"template": "模版",
|
||||
"property": "设定属性",
|
||||
"property": "属性",
|
||||
"format": "语法高亮",
|
||||
"syntax": "格式",
|
||||
"output": "输出为",
|
||||
@ -784,20 +784,6 @@
|
||||
"pythoncommandnotfound": "nrpgio python命令未处于运行状态"
|
||||
}
|
||||
},
|
||||
"tail": {
|
||||
"label": {
|
||||
"filename": "文件名",
|
||||
"type": "文件类型",
|
||||
"splitlines": "以\\n来拆分行?"
|
||||
},
|
||||
"action": {
|
||||
"text": "文本 - 返回字符串",
|
||||
"binary": "二进制 - 返回Buffer"
|
||||
},
|
||||
"errors": {
|
||||
"windowsnotsupport": "Windows目前不支持."
|
||||
}
|
||||
},
|
||||
"file": {
|
||||
"label": {
|
||||
"filename": "文件名",
|
||||
|
@ -1,34 +1,38 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"ajv": "6.5.4",
|
||||
"ajv": "6.6.1",
|
||||
"body-parser": "1.18.3",
|
||||
"cheerio": "0.22.0",
|
||||
"cookie-parser": "1.4.3",
|
||||
"cookie": "0.3.1",
|
||||
"cors": "2.8.4",
|
||||
"cron": "1.5.0",
|
||||
"denque": "1.3.0",
|
||||
"fs-extra": "5.0.0",
|
||||
"cors": "2.8.5",
|
||||
"cron": "1.5.1",
|
||||
"denque": "1.4.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"fs.notify": "0.0.4",
|
||||
"hash-sum": "1.0.2",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.12.0",
|
||||
"media-typer": "0.3.0",
|
||||
"media-typer": "1.0.1",
|
||||
"mqtt": "2.18.8",
|
||||
"multer": "1.4.1",
|
||||
"mustache": "2.3.2",
|
||||
"mustache": "3.0.1",
|
||||
"on-headers": "1.0.1",
|
||||
"raw-body": "2.3.3",
|
||||
"request": "2.88.0",
|
||||
|
@ -14,6 +14,13 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/*
|
||||
* This provides a list of node types that have at one time been included with
|
||||
* the core of Node-RED but have since moved out to their own module.
|
||||
*
|
||||
* If a user has a flow that depends on one of these types and they do not have
|
||||
* the new module installed, this will help them identify the missing module.
|
||||
*/
|
||||
var nodes = {
|
||||
"irc in": {module:"node-red-node-irc"},
|
||||
"irc out": {module:"node-red-node-irc"},
|
||||
@ -39,7 +46,11 @@ var nodes = {
|
||||
"e-mail": {module:"node-red-node-email"},
|
||||
"e-mail in": {module:"node-red-node-email"},
|
||||
|
||||
"feedparse": {module:"node-red-node-feedparser"}
|
||||
"feedparse": {module:"node-red-node-feedparser"},
|
||||
|
||||
"sentiment": {module:"node-red-node-sentiment"},
|
||||
|
||||
"tail": {module:"node-red-node-tail"}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -235,13 +235,18 @@ function checkPrereq() {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
child_process.execFile(npmCommand,['-v'],function(err) {
|
||||
child_process.execFile(npmCommand,['-v'],function(err,stdout) {
|
||||
if (err) {
|
||||
log.info(log._("server.palette-editor.npm-not-found"));
|
||||
paletteEditorEnabled = false;
|
||||
} else {
|
||||
if (parseInt(stdout.split(".")[0]) < 3) {
|
||||
log.info(log._("server.palette-editor.npm-too-old"));
|
||||
paletteEditorEnabled = false;
|
||||
} else {
|
||||
paletteEditorEnabled = true;
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
|
@ -21,8 +21,8 @@ var semver = require("semver");
|
||||
|
||||
var localfilesystem = require("./localfilesystem");
|
||||
var registry = require("./registry");
|
||||
|
||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
||||
var registryUtil = require("./util")
|
||||
var i18n = require("@node-red/util").i18n;
|
||||
|
||||
var settings;
|
||||
var runtime;
|
||||
@ -31,6 +31,7 @@ function init(_runtime) {
|
||||
runtime = _runtime;
|
||||
settings = runtime.settings;
|
||||
localfilesystem.init(runtime);
|
||||
registryUtil.init(runtime);
|
||||
}
|
||||
|
||||
function load(defaultNodesDir,disableNodePathScan) {
|
||||
@ -44,92 +45,6 @@ function load(defaultNodesDir,disableNodePathScan) {
|
||||
return loadNodeFiles(nodeFiles);
|
||||
}
|
||||
|
||||
function copyObjectProperties(src,dst,copyList,blockList) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
if (copyList && !blockList) {
|
||||
copyList.forEach(function(i) {
|
||||
if (src.hasOwnProperty(i)) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
|
||||
Object.defineProperty(dst,i,propDescriptor);
|
||||
}
|
||||
});
|
||||
} else if (!copyList && blockList) {
|
||||
for (var i in src) {
|
||||
if (src.hasOwnProperty(i) && blockList.indexOf(i) === -1) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
|
||||
Object.defineProperty(dst,i,propDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function requireModule(name) {
|
||||
var moduleInfo = registry.getModuleInfo(name);
|
||||
if (moduleInfo && moduleInfo.path) {
|
||||
var relPath = path.relative(__dirname, moduleInfo.path);
|
||||
return require(relPath);
|
||||
} else {
|
||||
var err = new Error(`Cannot find module '${name}'`);
|
||||
err.code = "MODULE_NOT_FOUND";
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function createNodeApi(node) {
|
||||
var red = {
|
||||
nodes: {},
|
||||
log: {},
|
||||
settings: {},
|
||||
events: runtime.events,
|
||||
util: runtime.util,
|
||||
version: runtime.version,
|
||||
require: requireModule,
|
||||
comms: {
|
||||
publish: function(topic,data,retain) {
|
||||
runtime.events.emit("comms",{
|
||||
topic: topic,
|
||||
data: data,
|
||||
retain: retain
|
||||
})
|
||||
}
|
||||
},
|
||||
library: {
|
||||
register: function(type) {
|
||||
return runtime.library.register(node.id,type);
|
||||
}
|
||||
},
|
||||
httpNode: runtime.nodeApp,
|
||||
server: runtime.server
|
||||
}
|
||||
copyObjectProperties(runtime.nodes,red.nodes,["createNode","getNode","eachNode","addCredentials","getCredentials","deleteCredentials" ]);
|
||||
red.nodes.registerType = function(type,constructor,opts) {
|
||||
runtime.nodes.registerType(node.id,type,constructor,opts);
|
||||
}
|
||||
copyObjectProperties(runtime.log,red.log,null,["init"]);
|
||||
copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]);
|
||||
if (runtime.adminApi) {
|
||||
red.auth = runtime.adminApi.auth;
|
||||
red.httpAdmin = runtime.adminApi.adminApp;
|
||||
} else {
|
||||
//TODO: runtime.adminApi is always stubbed if not enabled, so this block
|
||||
// is unused - but may be needed for the unit tests
|
||||
red.auth = {
|
||||
needsPermission: function() {}
|
||||
};
|
||||
// TODO: stub out httpAdmin/httpNode/server
|
||||
}
|
||||
red["_"] = function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
if (args[0].indexOf(":") === -1) {
|
||||
args[0] = node.namespace+":"+args[0];
|
||||
}
|
||||
return i18n._.apply(null,args);
|
||||
}
|
||||
return red;
|
||||
}
|
||||
|
||||
|
||||
function loadNodeFiles(nodeFiles) {
|
||||
var promises = [];
|
||||
var nodes = [];
|
||||
@ -332,7 +247,7 @@ function loadNodeSet(node) {
|
||||
var r = require(node.file);
|
||||
if (typeof r === "function") {
|
||||
|
||||
var red = createNodeApi(node);
|
||||
var red = registryUtil.createNodeApi(node);
|
||||
var promise = r(red);
|
||||
if (promise != null && typeof promise.then === "function") {
|
||||
loadPromise = promise.then(function() {
|
||||
|
110
packages/node_modules/@node-red/registry/lib/util.js
vendored
Normal file
110
packages/node_modules/@node-red/registry/lib/util.js
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var i18n = require("@node-red/util").i18n;
|
||||
var runtime;
|
||||
|
||||
function copyObjectProperties(src,dst,copyList,blockList) {
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
if (copyList && !blockList) {
|
||||
copyList.forEach(function(i) {
|
||||
if (src.hasOwnProperty(i)) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
|
||||
Object.defineProperty(dst,i,propDescriptor);
|
||||
}
|
||||
});
|
||||
} else if (!copyList && blockList) {
|
||||
for (var i in src) {
|
||||
if (src.hasOwnProperty(i) && blockList.indexOf(i) === -1) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
|
||||
Object.defineProperty(dst,i,propDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function requireModule(name) {
|
||||
var moduleInfo = registry.getModuleInfo(name);
|
||||
if (moduleInfo && moduleInfo.path) {
|
||||
var relPath = path.relative(__dirname, moduleInfo.path);
|
||||
return require(relPath);
|
||||
} else {
|
||||
var err = new Error(`Cannot find module '${name}'`);
|
||||
err.code = "MODULE_NOT_FOUND";
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function createNodeApi(node) {
|
||||
var red = {
|
||||
nodes: {},
|
||||
log: {},
|
||||
settings: {},
|
||||
events: runtime.events,
|
||||
util: runtime.util,
|
||||
version: runtime.version,
|
||||
require: requireModule,
|
||||
comms: {
|
||||
publish: function(topic,data,retain) {
|
||||
runtime.events.emit("comms",{
|
||||
topic: topic,
|
||||
data: data,
|
||||
retain: retain
|
||||
})
|
||||
}
|
||||
},
|
||||
library: {
|
||||
register: function(type) {
|
||||
return runtime.library.register(node.id,type);
|
||||
}
|
||||
},
|
||||
httpNode: runtime.nodeApp,
|
||||
httpAdmin: runtime.adminApp,
|
||||
server: runtime.server
|
||||
}
|
||||
copyObjectProperties(runtime.nodes,red.nodes,["createNode","getNode","eachNode","addCredentials","getCredentials","deleteCredentials" ]);
|
||||
red.nodes.registerType = function(type,constructor,opts) {
|
||||
runtime.nodes.registerType(node.id,type,constructor,opts);
|
||||
}
|
||||
copyObjectProperties(runtime.log,red.log,null,["init"]);
|
||||
copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]);
|
||||
if (runtime.adminApi) {
|
||||
red.auth = runtime.adminApi.auth;
|
||||
} else {
|
||||
//TODO: runtime.adminApi is always stubbed if not enabled, so this block
|
||||
// is unused - but may be needed for the unit tests
|
||||
red.auth = {
|
||||
needsPermission: function(v) { return function(req,res,next) {next()} }
|
||||
};
|
||||
// TODO: stub out httpAdmin/httpNode/server
|
||||
}
|
||||
red["_"] = function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
if (args[0].indexOf(":") === -1) {
|
||||
args[0] = node.namespace+":"+args[0];
|
||||
}
|
||||
return i18n._.apply(null,args);
|
||||
}
|
||||
return red;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtime) {
|
||||
runtime = _runtime;
|
||||
},
|
||||
createNodeApi: createNodeApi
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -8,11 +8,15 @@
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "*",
|
||||
"@node-red/util": "0.20.0-beta.2",
|
||||
"semver": "5.6.0",
|
||||
"uglify-js": "3.4.9",
|
||||
"when": "3.7.8"
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*!
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -17,3 +17,27 @@
|
||||
var events = require("events");
|
||||
|
||||
module.exports = new events.EventEmitter();
|
||||
|
||||
/**
|
||||
* Runtime events emitter
|
||||
* @mixin @node-red/runtime_events
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register an event listener for a runtime event
|
||||
* @name on
|
||||
* @function
|
||||
* @memberof @node-red/runtime_events
|
||||
* @param {String} eventName - the name of the event to listen to
|
||||
* @param {Function} listener - the callback function for the event
|
||||
*/
|
||||
|
||||
/**
|
||||
* Emit an event to all of its registered listeners
|
||||
* @name emit
|
||||
* @function
|
||||
* @memberof @node-red/runtime_events
|
||||
* @param {String} eventName - the name of the event to emit
|
||||
* @param {any} ...args - the arguments to pass in the event
|
||||
* @return {Boolean} - whether the event had listeners or not
|
||||
*/
|
||||
|
@ -53,6 +53,7 @@ var adminApi = {
|
||||
}
|
||||
|
||||
var nodeApp;
|
||||
var adminApp;
|
||||
var server;
|
||||
|
||||
|
||||
@ -64,12 +65,13 @@ var server;
|
||||
* better abstracted.
|
||||
* @memberof @node-red/runtime
|
||||
*/
|
||||
function init(userSettings,httpServer,_adminApi) {
|
||||
function init(userSettings,httpServer,_adminApi,__util) {
|
||||
server = httpServer;
|
||||
userSettings.version = getVersion();
|
||||
settings.init(userSettings);
|
||||
|
||||
nodeApp = express();
|
||||
adminApp = express();
|
||||
|
||||
if (_adminApi) {
|
||||
adminApi = _adminApi;
|
||||
@ -78,6 +80,13 @@ function init(userSettings,httpServer,_adminApi) {
|
||||
library.init(runtime);
|
||||
externalAPI.init(runtime);
|
||||
exec.init(runtime);
|
||||
if (__util) {
|
||||
log = __util.log;
|
||||
i18n = __util.i18n;
|
||||
} else {
|
||||
log = redUtil.log;
|
||||
i18n = redUtil.i18n;
|
||||
}
|
||||
}
|
||||
|
||||
var version;
|
||||
@ -103,7 +112,6 @@ function getVersion() {
|
||||
* @memberof @node-red/runtime
|
||||
*/
|
||||
function start() {
|
||||
|
||||
return i18n.registerMessageCatalog("runtime",path.resolve(path.join(__dirname,"..","locales")),"runtime.json")
|
||||
.then(function() { return storage.init(runtime)})
|
||||
.then(function() { return settings.load(storage)})
|
||||
@ -269,6 +277,7 @@ var runtime = {
|
||||
exec: exec,
|
||||
util: require("@node-red/util").util,
|
||||
get adminApi() { return adminApi },
|
||||
get adminApp() { return adminApp },
|
||||
get nodeApp() { return nodeApp },
|
||||
get server() { return server },
|
||||
isStarted: function() {
|
||||
@ -346,8 +355,12 @@ module.exports = {
|
||||
|
||||
storage: storage,
|
||||
events: events,
|
||||
util: require("@node-red/util").util,
|
||||
get httpNode() { return nodeApp },
|
||||
get server() { return server }
|
||||
get httpAdmin() { return adminApp },
|
||||
get server() { return server },
|
||||
|
||||
"_": runtime
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
"loading": "Loading palette nodes",
|
||||
"palette-editor": {
|
||||
"disabled": "Palette editor disabled : user settings",
|
||||
"npm-not-found": "Palette editor disabled : npm command not found"
|
||||
"npm-not-found": "Palette editor disabled : npm command not found",
|
||||
"npm-too-old": "Palette editor disabled : npm version too old. Requires npm >= 3.x"
|
||||
},
|
||||
"errors": "Failed to register __count__ node type",
|
||||
"errors_plural": "Failed to register __count__ node types",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -8,15 +8,19 @@
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "*",
|
||||
"@node-red/util": "*",
|
||||
"@node-red/registry": "0.20.0-beta.2",
|
||||
"@node-red/util": "0.20.0-beta.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.16.4",
|
||||
"fs-extra": "5.0.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"when": "3.7.8"
|
||||
}
|
||||
|
20
packages/node_modules/@node-red/util/index.js
vendored
20
packages/node_modules/@node-red/util/index.js
vendored
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*!
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -14,17 +14,20 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
/**
|
||||
* @module @node-red/util
|
||||
*/
|
||||
const log = require("./lib/log");
|
||||
const i18n = require("./lib/i18n");
|
||||
const util = require("./lib/util");
|
||||
|
||||
/**
|
||||
* This module provides common utilities for the Node-RED runtime and editor
|
||||
*
|
||||
* @namespace @node-red/util
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* Initialise the module with the runtime settings
|
||||
* @param {Object} settings
|
||||
* @memberof @node-red/util
|
||||
*/
|
||||
init: function(settings) {
|
||||
log.init(settings);
|
||||
@ -33,19 +36,22 @@ module.exports = {
|
||||
|
||||
/**
|
||||
* Logging utilities
|
||||
* @see module:@node-red/util.module:log
|
||||
* @mixes @node-red/util_log
|
||||
* @memberof @node-red/util
|
||||
*/
|
||||
log: log,
|
||||
|
||||
/**
|
||||
* Internationalization utilities
|
||||
* @see module:@node-red/util.module:i18n
|
||||
* @mixes @node-red/util_i18n
|
||||
* @memberof @node-red/util
|
||||
*/
|
||||
i18n: i18n,
|
||||
|
||||
/**
|
||||
* General utilities
|
||||
* @see module:@node-red/util.module:util
|
||||
* @mixes @node-red/util_util
|
||||
* @memberof @node-red/util
|
||||
*/
|
||||
util: util,
|
||||
}
|
||||
|
12
packages/node_modules/@node-red/util/lib/i18n.js
vendored
12
packages/node_modules/@node-red/util/lib/i18n.js
vendored
@ -16,8 +16,8 @@
|
||||
**/
|
||||
|
||||
/**
|
||||
* @module i18n
|
||||
* @memberof module:@node-red/util
|
||||
* Internationalization utilities
|
||||
* @mixin @node-red/util_i18n
|
||||
*/
|
||||
|
||||
var i18n = require("i18next");
|
||||
@ -34,7 +34,7 @@ var initPromise;
|
||||
|
||||
/**
|
||||
* Register multiple message catalogs with i18n.
|
||||
* @memberof module:@node-red/util.module:i18n
|
||||
* @memberof @node-red/util_i18n
|
||||
*/
|
||||
function registerMessageCatalogs(catalogs) {
|
||||
var promises = catalogs.map(function(catalog) {
|
||||
@ -45,7 +45,7 @@ function registerMessageCatalogs(catalogs) {
|
||||
|
||||
/**
|
||||
* Register a message catalog with i18n.
|
||||
* @memberof module:@node-red/util.module:i18n
|
||||
* @memberof @node-red/util_i18n
|
||||
*/
|
||||
function registerMessageCatalog(namespace,dir,file) {
|
||||
return initPromise.then(function() {
|
||||
@ -146,7 +146,7 @@ function init() {
|
||||
* Gets a message catalog.
|
||||
* @name catalog
|
||||
* @function
|
||||
* @memberof module:@node-red/util.module:i18n
|
||||
* @memberof @node-red/util_i18n
|
||||
*/
|
||||
function getCatalog(namespace,lang) {
|
||||
var result = null;
|
||||
@ -182,7 +182,7 @@ var obj = module.exports = {
|
||||
* Perform a message catalog lookup.
|
||||
* @name _
|
||||
* @function
|
||||
* @memberof module:@node-red/util.module:i18n
|
||||
* @memberof @node-red/util_i18n
|
||||
*/
|
||||
obj['_'] = function() {
|
||||
//var opts = {};
|
||||
|
34
packages/node_modules/@node-red/util/lib/log.js
vendored
34
packages/node_modules/@node-red/util/lib/log.js
vendored
@ -16,8 +16,8 @@
|
||||
**/
|
||||
|
||||
/**
|
||||
* @module log
|
||||
* @memberof module:@node-red/util
|
||||
* Logging utilities
|
||||
* @mixin @node-red/util_log
|
||||
*/
|
||||
|
||||
var util = require("util");
|
||||
@ -128,14 +128,16 @@ var log = module.exports = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a log handler function.
|
||||
* Add a log handler function
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
addHandler: function(func) {
|
||||
logHandlers.push(func);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a log handler function.
|
||||
* Remove a log handler function
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
removeHandler: function(func) {
|
||||
var index = logHandlers.indexOf(func);
|
||||
@ -145,7 +147,8 @@ var log = module.exports = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message object.
|
||||
* Log a message object
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
log: function(msg) {
|
||||
msg.timestamp = Date.now();
|
||||
@ -155,42 +158,48 @@ var log = module.exports = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message at INFO level.
|
||||
* Log a message at INFO level
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
info: function(msg) {
|
||||
log.log({level:log.INFO,msg:msg});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message at WARN level.
|
||||
* Log a message at WARN level
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
warn: function(msg) {
|
||||
log.log({level:log.WARN,msg:msg});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message at ERROR level.
|
||||
* Log a message at ERROR level
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
error: function(msg) {
|
||||
log.log({level:log.ERROR,msg:msg});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message at TRACE level.
|
||||
* Log a message at TRACE level
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
trace: function(msg) {
|
||||
log.log({level:log.TRACE,msg:msg});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a message at DEBUG level.
|
||||
* Log a message at DEBUG level
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
debug: function(msg) {
|
||||
log.log({level:log.DEBUG,msg:msg});
|
||||
},
|
||||
|
||||
/**
|
||||
* Log a metric event.
|
||||
* Check if metrics are enabled
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
metric: function() {
|
||||
return metricsEnabled;
|
||||
@ -198,6 +207,7 @@ var log = module.exports = {
|
||||
|
||||
/**
|
||||
* Log an audit event.
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
audit: function(msg,req) {
|
||||
msg.level = log.AUDIT;
|
||||
@ -214,6 +224,6 @@ var log = module.exports = {
|
||||
* Perform a message catalog lookup.
|
||||
* @name _
|
||||
* @function
|
||||
* @memberof module:@node-red/util.module:log
|
||||
* @memberof @node-red/util_log
|
||||
*/
|
||||
log["_"] = i18n._;
|
||||
|
37
packages/node_modules/@node-red/util/lib/util.js
vendored
37
packages/node_modules/@node-red/util/lib/util.js
vendored
@ -16,8 +16,7 @@
|
||||
**/
|
||||
|
||||
/**
|
||||
* @module util
|
||||
* @memberof module:@node-red/util
|
||||
* @mixin @node-red/util_util
|
||||
*/
|
||||
|
||||
|
||||
@ -29,7 +28,7 @@ const util = require("util");
|
||||
/**
|
||||
* Generates a psuedo-unique-random id.
|
||||
* @return {String} a random-ish id
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function generateId() {
|
||||
return (1+Math.random()*4294967295).toString(16);
|
||||
@ -41,7 +40,7 @@ function generateId() {
|
||||
*
|
||||
* @param {any} o - the property to convert to a String
|
||||
* @return {String} the stringified version
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function ensureString(o) {
|
||||
if (Buffer.isBuffer(o)) {
|
||||
@ -60,7 +59,7 @@ function ensureString(o) {
|
||||
*
|
||||
* @param {any} o - the property to convert to a Buffer
|
||||
* @return {String} the Buffer version
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function ensureBuffer(o) {
|
||||
if (Buffer.isBuffer(o)) {
|
||||
@ -79,7 +78,7 @@ function ensureBuffer(o) {
|
||||
*
|
||||
* @param {any} msg - the message object to clone
|
||||
* @return {Object} the cloned message
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function cloneMessage(msg) {
|
||||
// Temporary fix for #97
|
||||
@ -106,7 +105,7 @@ function cloneMessage(msg) {
|
||||
* @param {any} obj1
|
||||
* @param {any} obj2
|
||||
* @return {boolean} whether the two objects are the same
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function compareObjects(obj1,obj2) {
|
||||
var i;
|
||||
@ -189,7 +188,7 @@ function createError(code, message) {
|
||||
*
|
||||
* @param {String} str - the property expression
|
||||
* @return {Array} the normalised expression
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function normalisePropertyExpression(str) {
|
||||
// This must be kept in sync with validatePropertyExpression
|
||||
@ -304,7 +303,7 @@ function normalisePropertyExpression(str) {
|
||||
* @param {Object} msg - the message object
|
||||
* @param {String} str - the property expression
|
||||
* @return {any} the message property, or undefined if it does not exist
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function getMessageProperty(msg,expr) {
|
||||
if (expr.indexOf('msg.')===0) {
|
||||
@ -319,7 +318,7 @@ function getMessageProperty(msg,expr) {
|
||||
* @param {Object} msg - the object
|
||||
* @param {String} str - the property expression
|
||||
* @return {any} the object property, or undefined if it does not exist
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function getObjectProperty(msg,expr) {
|
||||
var result = null;
|
||||
@ -342,7 +341,7 @@ function getObjectProperty(msg,expr) {
|
||||
* @param {String} prop - the property expression
|
||||
* @param {any} value - the value to set
|
||||
* @param {boolean} createMissing - whether to create missing parent properties
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function setMessageProperty(msg,prop,value,createMissing) {
|
||||
if (prop.indexOf('msg.')===0) {
|
||||
@ -358,7 +357,7 @@ function setMessageProperty(msg,prop,value,createMissing) {
|
||||
* @param {String} prop - the property expression
|
||||
* @param {any} value - the value to set
|
||||
* @param {boolean} createMissing - whether to create missing parent properties
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function setObjectProperty(msg,prop,value,createMissing) {
|
||||
if (typeof createMissing === 'undefined') {
|
||||
@ -422,7 +421,7 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
* will return `Hello Joe!`.
|
||||
* @param {String} value - the string to parse
|
||||
* @return {String} The parsed string
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateEnvProperty(value) {
|
||||
if (/^\${[^}]+}$/.test(value)) {
|
||||
@ -450,7 +449,7 @@ function evaluateEnvProperty(value) {
|
||||
*
|
||||
* @param {String} value - the context property string to parse
|
||||
* @return {Object} The parsed property
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function parseContextStore(key) {
|
||||
var parts = {};
|
||||
@ -474,7 +473,7 @@ function parseContextStore(key) {
|
||||
* @param {Object} msg - the message object to evaluate against
|
||||
* @param {Function} callback - (optional) called when the property is evaluated
|
||||
* @return {any} The evaluted property, if no `callback` is provided
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
var result = value;
|
||||
@ -531,7 +530,7 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
* @param {String} value - the JSONata expression
|
||||
* @param {Node} node - the node evaluating the property
|
||||
* @return {Object} The JSONata expression that can be evaluated
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function prepareJSONataExpression(value,node) {
|
||||
var expr = jsonata(value);
|
||||
@ -559,7 +558,7 @@ function prepareJSONataExpression(value,node) {
|
||||
* @param {Object} msg - the message object to evaluate against
|
||||
* @param {Function} callback - (optional) called when the expression is evaluated
|
||||
* @return {any} If no callback was provided, the result of the expression
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateJSONataExpression(expr,msg,callback) {
|
||||
var context = msg;
|
||||
@ -604,7 +603,7 @@ function evaluateJSONataExpression(expr,msg,callback) {
|
||||
*
|
||||
* @param {String} name - the node type
|
||||
* @return {String} The normalised name
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function normaliseNodeTypeName(name) {
|
||||
var result = name.replace(/[^a-zA-Z0-9]/g, " ");
|
||||
@ -628,7 +627,7 @@ function normaliseNodeTypeName(name) {
|
||||
* @param {Object} msg
|
||||
* @param {Object} opts
|
||||
* @return {Object} the encoded object
|
||||
* @memberof module:@node-red/util.module:util
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function encodeObject(msg,opts) {
|
||||
var debuglength = 1000;
|
||||
|
@ -1,18 +1,22 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/node-red/node-red.git"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"clone": "2.1.2",
|
||||
"i18next": "11.6.0",
|
||||
"i18next": "12.1.0",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.5.4",
|
||||
"when": "3.7.8"
|
||||
|
1
packages/node_modules/node-red/.gitignore
vendored
Normal file
1
packages/node_modules/node-red/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
CHANGELOG.md
|
24
packages/node_modules/node-red/README.md
vendored
24
packages/node_modules/node-red/README.md
vendored
@ -9,11 +9,6 @@ A visual tool for wiring the Internet of Things.
|
||||
|
||||
![Node-RED: A visual tool for wiring the Internet of Things](http://nodered.org/images/node-red-screenshot.png)
|
||||
|
||||
### Repository Structure
|
||||
|
||||
This is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) containing the source
|
||||
code for all of the Node-RED component modules.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
@ -31,24 +26,7 @@ For further help, or general discussion, please use the [Node-RED Forum](https:/
|
||||
|
||||
## Developers
|
||||
|
||||
If you want to run the latest code from git, here's how to get started:
|
||||
|
||||
1. Clone the code:
|
||||
|
||||
git clone https://github.com/node-red/node-red.git
|
||||
cd node-red
|
||||
|
||||
2. Install the node-red dependencies
|
||||
|
||||
npm install
|
||||
|
||||
3. Build the code
|
||||
|
||||
npm run build
|
||||
|
||||
4. Run
|
||||
|
||||
npm start
|
||||
The main Node-RED modules are maintained as a monorepo on [GitHub](https://github.com/node-red/node-red).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
42
packages/node_modules/node-red/lib/red.js
vendored
42
packages/node_modules/node-red/lib/red.js
vendored
@ -63,8 +63,13 @@ module.exports = {
|
||||
}
|
||||
redUtil.init(userSettings);
|
||||
if (userSettings.httpAdminRoot !== false) {
|
||||
// Initialise the runtime
|
||||
runtime.init(userSettings,httpServer,api);
|
||||
// Initialise the editor-api
|
||||
api.init(userSettings,httpServer,runtime.storage,runtime);
|
||||
// Attach the runtime admin app to the api admin app
|
||||
api.httpAdmin.use(runtime.httpAdmin);
|
||||
|
||||
apiEnabled = true;
|
||||
server = httpServer;
|
||||
} else {
|
||||
@ -103,19 +108,46 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Logging utilities
|
||||
* @see @node-red/util_log
|
||||
* @memberof node-red
|
||||
*/
|
||||
log: redUtil.log,
|
||||
|
||||
/**
|
||||
* General utilities
|
||||
* @see @node-red/util_util
|
||||
* @memberof node-red
|
||||
*/
|
||||
util: redUtil.util,
|
||||
|
||||
get nodes() { console.log("Deprecated use of RED.nodes - refer to API documentation on RED.runtime.nodes"); return runtime._.nodes },
|
||||
get settings() { console.log("Deprecated use of RED.settings - refer to API documentation on RED.runtime.settings"); return runtime._.settings },
|
||||
get version() { console.log("Deprecated use of RED.version - refer to API documentation on RED.runtime.version"); return runtime._.version },
|
||||
get events() { console.log("Deprecated use of RED.events - refer to API documentation on RED.runtime.events"); return runtime.events },
|
||||
get nodes() { return runtime._.nodes },
|
||||
|
||||
/**
|
||||
* Runtime events emitter
|
||||
* @see @node-red/runtime_events
|
||||
* @memberof node-red
|
||||
*/
|
||||
events: runtime.events,
|
||||
|
||||
get settings() { return runtime._.settings },
|
||||
|
||||
|
||||
/**
|
||||
* Get the version of the runtime
|
||||
* @return {String} - the runtime version
|
||||
* @function
|
||||
* @memberof node-red
|
||||
*/
|
||||
get version() { return runtime._.version },
|
||||
|
||||
|
||||
/**
|
||||
* The express application for the Editor Admin API
|
||||
* @memberof node-red
|
||||
*/
|
||||
get httpAdmin() { return api.adminApp },
|
||||
get httpAdmin() { return api.httpAdmin },
|
||||
|
||||
/**
|
||||
* The express application for HTTP Nodes
|
||||
|
26
packages/node_modules/node-red/package.json
vendored
26
packages/node_modules/node-red/package.json
vendored
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "0.20.0-alpha.0",
|
||||
"version": "0.20.0-beta.2",
|
||||
"description": "A visual tool for wiring the Internet of Things",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@ -17,8 +17,12 @@
|
||||
"node-red-pi": "bin/node-red-pi"
|
||||
},
|
||||
"contributors": [
|
||||
{ "name": "Nick O'Leary" },
|
||||
{ "name": "Dave Conway-Jones"}
|
||||
{
|
||||
"name": "Nick O'Leary"
|
||||
},
|
||||
{
|
||||
"name": "Dave Conway-Jones"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"editor",
|
||||
@ -27,17 +31,19 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "0.20.0-alpha.0",
|
||||
"@node-red/runtime": "0.20.0-alpha.0",
|
||||
"@node-red/util": "0.20.0-alpha.0",
|
||||
"@node-red/nodes": "0.20.0-alpha.0",
|
||||
"@node-red/editor-api": "0.20.0-beta.2",
|
||||
"@node-red/runtime": "0.20.0-beta.2",
|
||||
"@node-red/util": "0.20.0-beta.2",
|
||||
"@node-red/nodes": "0.20.0-beta.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.16.4",
|
||||
"fs-extra": "5.0.0",
|
||||
"node-red-node-email": "0.1.*",
|
||||
"node-red-node-feedparser": "^0.1.12",
|
||||
"fs-extra": "7.0.1",
|
||||
"node-red-node-email": "1.0.*",
|
||||
"node-red-node-feedparser": "^0.1.14",
|
||||
"node-red-node-rbe": "0.2.*",
|
||||
"node-red-node-sentiment": "^0.1.0",
|
||||
"node-red-node-tail": "^0.0.1",
|
||||
"node-red-node-twitter": "^1.1.0",
|
||||
"nopt": "4.0.1",
|
||||
"semver": "5.6.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const fs = require("fs-extra");
|
||||
const should = require("should");
|
||||
|
||||
const rootPackage = require(path.join("..","package.json"));
|
||||
@ -16,8 +16,11 @@ const packages = [
|
||||
"@node-red/util"
|
||||
];
|
||||
|
||||
const fixFlag = process.argv[2] === '--fix';
|
||||
|
||||
function verifyDependencies() {
|
||||
let failures = [];
|
||||
let packageUpdates = {};
|
||||
packages.forEach(package => {
|
||||
let modulePackage = require(path.join("../packages/node_modules",package,"package.json"));
|
||||
let dependencies = Object.keys(modulePackage.dependencies||{});
|
||||
@ -25,22 +28,48 @@ function verifyDependencies() {
|
||||
try {
|
||||
if (!/^@node-red\//.test(module)) {
|
||||
should.exist(rootDependencies[module],`[${package}] '${module}' missing from root package.json`);
|
||||
try {
|
||||
rootDependencies[module].should.eql(modulePackage.dependencies[module],`[${package}] '${module}' version mismatch. Expected '${modulePackage.dependencies[module]}' (got '${rootDependencies[module]}') `);
|
||||
} catch(err) {
|
||||
if (fixFlag) {
|
||||
modulePackage.dependencies[module] = rootDependencies[module];
|
||||
packageUpdates[package] = modulePackage;
|
||||
} else {
|
||||
failures.push(err.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
failures.push(err.toString());
|
||||
}
|
||||
});
|
||||
})
|
||||
return failures;
|
||||
if (failures.length === 0 && fixFlag) {
|
||||
var promises = [];
|
||||
packages.forEach(package => {
|
||||
if (packageUpdates.hasOwnProperty(package)) {
|
||||
promises.push(fs.writeJSON(path.join(__dirname,"../packages/node_modules",package,"package.json"),packageUpdates[package],{spaces:4}));
|
||||
}
|
||||
});
|
||||
return Promise.all(promises).then(r => []).catch(e => {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
})
|
||||
} else {
|
||||
return Promise.resolve(failures);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
let failures = verifyDependencies();
|
||||
verifyDependencies().then(failures => {
|
||||
if (failures.length > 0) {
|
||||
failures.forEach(f => console.log(` - ${f}`));
|
||||
process.exit(1);
|
||||
}
|
||||
}).catch(e => {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
module.exports = verifyDependencies;
|
||||
}
|
||||
|
@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sentimentNode = require("nr-test-utils").require("@node-red/nodes/core/analysis/72-sentiment.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('sentiment Node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"sentimentNode1", type:"sentiment", name: "sentimentNode" }];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var sentimentNode1 = helper.getNode("sentimentNode1");
|
||||
sentimentNode1.should.have.property('name', 'sentimentNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass on msg if no payload', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.not.have.property('sentiment');
|
||||
msg.topic.should.equal("pass on");
|
||||
done();
|
||||
});
|
||||
var testString = 'good, great, best, brilliant';
|
||||
jn1.receive({topic:"pass on"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a positive score for good words', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.be.above(10);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var testString = 'good, great, best, brilliant';
|
||||
jn1.receive({payload:testString});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a positive score for good words - alternative property', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",property:"foo",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.be.above(10);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var testString = 'good, great, best, brilliant';
|
||||
jn1.receive({foo:testString});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a negative score for bad words', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.be.below(-10);
|
||||
done();
|
||||
});
|
||||
var testString = 'bad, horrible, negative, awful';
|
||||
jn1.receive({payload:testString});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a negative score for bad words - alternative property', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",property:"foo",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.be.below(-10);
|
||||
done();
|
||||
});
|
||||
var testString = 'bad, horrible, negative, awful';
|
||||
jn1.receive({foo:testString});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow you to override word scoring', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.equal(20);
|
||||
done();
|
||||
});
|
||||
var testString = 'sick, wicked';
|
||||
var overrides = {'sick': 10, 'wicked': 10 };
|
||||
jn1.receive({payload:testString,overrides:overrides});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow you to override word scoring - alternative property', function(done) {
|
||||
var flow = [{id:"jn1",type:"sentiment",property:"foo",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(sentimentNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('sentiment');
|
||||
msg.sentiment.should.have.property('score');
|
||||
msg.sentiment.score.should.be.a.Number();
|
||||
msg.sentiment.score.should.equal(20);
|
||||
done();
|
||||
});
|
||||
var testString = 'sick, wicked';
|
||||
var overrides = {'sick': 10, 'wicked': 10 };
|
||||
jn1.receive({foo:testString,overrides:overrides});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -503,16 +503,21 @@ describe('inject node', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
try {
|
||||
helper.request()
|
||||
.post('/inject/n1')
|
||||
.expect(200).end(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return helper.clearFlows()
|
||||
.then(function () {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -207,6 +207,12 @@ describe('HTTP Request Node', function() {
|
||||
res.cookie('redirectToDifferentDomain','different1');
|
||||
res.redirect(getDifferentTestURL('/redirectReturn'));
|
||||
});
|
||||
testApp.get('/redirectMultipleTimes', function(req, res) {
|
||||
var key = req.headers.host + req.url;
|
||||
receivedCookies[key] = req.cookies;
|
||||
res.cookie('redirectMultipleTimes','multiple1');
|
||||
res.redirect(getTestURL('/redirectToDifferentDomain'));
|
||||
});
|
||||
testApp.get('/redirectReturn', function(req, res) {
|
||||
var key = req.headers.host + req.url;
|
||||
receivedCookies[key] = req.cookies;
|
||||
@ -277,6 +283,7 @@ describe('HTTP Request Node', function() {
|
||||
msg.should.have.property('headers');
|
||||
msg.headers.should.have.property('content-length',''+('hello'.length));
|
||||
msg.headers.should.have.property('content-type').which.startWith('text/html');
|
||||
msg.redirectList.length.should.equal(0);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
@ -1510,6 +1517,10 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
|
||||
done();
|
||||
});
|
||||
n1.receive({});
|
||||
@ -1533,6 +1544,10 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://127.0.0.1:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToDifferentDomain.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToDifferentDomain.value.should.equal('different1');
|
||||
done();
|
||||
});
|
||||
n1.receive({});
|
||||
@ -1559,6 +1574,10 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
|
||||
done();
|
||||
});
|
||||
n1.receive({
|
||||
@ -1585,6 +1604,10 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://127.0.0.1:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToDifferentDomain.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToDifferentDomain.value.should.equal('different1');
|
||||
done();
|
||||
});
|
||||
n1.receive({
|
||||
@ -1613,6 +1636,10 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToSameDomainCookie.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToSameDomainCookie.value.should.equal('same1');
|
||||
done();
|
||||
});
|
||||
n1.receive({
|
||||
@ -1639,6 +1666,33 @@ describe('HTTP Request Node', function() {
|
||||
done(new Error('Invalid cookie(path:/rediectReurn)'));
|
||||
return;
|
||||
}
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://127.0.0.1:'+testPort+'/redirectReturn');
|
||||
redirect1.cookies.redirectToDifferentDomain.Path.should.equal('/');
|
||||
redirect1.cookies.redirectToDifferentDomain.value.should.equal('different1');
|
||||
done();
|
||||
});
|
||||
n1.receive({
|
||||
headers: { cookie: 'requestCookie=request1' }
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should return all redirect information when redirected multiple times', function(done) {
|
||||
var flow = [{id:'n1',type:'http request',wires:[['n2']],method:'GET',ret:'obj',url:getTestURL('/redirectMultipleTimes')},
|
||||
{id:"n2", type:"helper"}];
|
||||
receivedCookies = {};
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
var redirect1 = msg.redirectList[0];
|
||||
redirect1.location.should.equal('http://localhost:'+testPort+'/redirectToDifferentDomain');
|
||||
redirect1.cookies.redirectMultipleTimes.Path.should.equal('/');
|
||||
redirect1.cookies.redirectMultipleTimes.value.should.equal('multiple1');
|
||||
var redirect2 = msg.redirectList[1];
|
||||
redirect2.location.should.equal('http://127.0.0.1:'+testPort+'/redirectReturn');
|
||||
redirect2.cookies.redirectToDifferentDomain.Path.should.equal('/');
|
||||
redirect2.cookies.redirectToDifferentDomain.value.should.equal('different1');
|
||||
done();
|
||||
});
|
||||
n1.receive({
|
||||
|
@ -1,206 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var path = require('path');
|
||||
var os = require('os');
|
||||
var fs = require('fs-extra');
|
||||
var sinon = require('sinon');
|
||||
var tailNode = require("nr-test-utils").require("@node-red/nodes/core/storage/28-tail.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('tail Node', function() {
|
||||
|
||||
var wait = 150;
|
||||
var resourcesDir = path.join(__dirname,"..","..","..","resources");
|
||||
var fileToTail = path.join(resourcesDir,"28-tail-test-file.txt");
|
||||
|
||||
beforeEach(function(done) {
|
||||
fs.writeFileSync(fileToTail, "Tail message line 1\nTail message line 2\n");
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload().then(function() {
|
||||
fs.unlinkSync(fileToTail);
|
||||
helper.stopServer(done);
|
||||
});
|
||||
});
|
||||
|
||||
if (os.type() !== "Windows_NT") {
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
tailNode1.should.have.property('name', 'tailNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should tail a file', function(done) {
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var inputCounter = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
msg.should.have.property('topic', fileToTail);
|
||||
msg.payload.should.equal("Tail message line " + (++inputCounter + 2));
|
||||
if (inputCounter === 2) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
setTimeout( function() {
|
||||
fs.appendFileSync(fileToTail, "Tail message line 3\n");
|
||||
fs.appendFileSync(fileToTail, "Tail message line 4\n");
|
||||
},wait);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work in non-split mode', function(done) {
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":false, "filename":fileToTail, "wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
msg.should.have.property('topic', fileToTail);
|
||||
msg.payload.should.equal("Tail message line 5\nTail message line 6\n");
|
||||
done();
|
||||
});
|
||||
setTimeout( function() {
|
||||
fs.appendFileSync(fileToTail, "Tail message line 5\nTail message line 6\n");
|
||||
},wait);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work in binary mode', function(done) {
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "filetype":"binary", "filename":fileToTail, "wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
msg.should.have.property('topic', fileToTail);
|
||||
msg.payload.toString().should.equal("Tail message line 7\nTail message line 8\n");
|
||||
done();
|
||||
});
|
||||
setTimeout( function() {
|
||||
fs.appendFileSync(fileToTail, "Tail message line 7\nTail message line 8\n");
|
||||
},wait);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle a non-existent file', function(done) {
|
||||
fs.writeFileSync(fileToTail, "Tail message line.\n");
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.property('topic', fileToTail);
|
||||
msg.payload.should.equal("Tail message line");
|
||||
done();
|
||||
});
|
||||
setTimeout(function() {
|
||||
fs.unlinkSync(fileToTail);
|
||||
},500);
|
||||
setTimeout( function() {
|
||||
fs.writeFile(fileToTail, "Tail message line\n");
|
||||
},1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('should throw an error if run on Windows', function() {
|
||||
// Stub os platform so we can make it look like windows
|
||||
var os = require('os');
|
||||
var spy = sinon.stub(os, 'platform', function(arg) { return("windows"); });
|
||||
|
||||
/*jshint immed: false */
|
||||
try {
|
||||
(function() { tailNode("1234"); }).should.throw();
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
finally {
|
||||
os.platform.restore();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
it('tail should handle file truncation', function(done) {
|
||||
var flow = [{id:"tailNode1", type:"tail", name: "tailNode", "split":true, "filename":fileToTail, "wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(tailNode, flow, function() {
|
||||
var tailNode1 = helper.getNode("tailNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var inputCounter = 0;
|
||||
var warned = false;
|
||||
tailNode1.on("log", function(msg) {
|
||||
if (msg.level == "warn") { warned = true; }
|
||||
});
|
||||
helperNode1.on("input", function(msg) {
|
||||
console.log("inputCounter =",inputCounter);
|
||||
console.log(msg);
|
||||
msg.should.have.property('topic', fileToTail);
|
||||
inputCounter++;
|
||||
if (inputCounter === 1) {
|
||||
warned.should.be.false();
|
||||
msg.payload.should.equal("Tail message line append");
|
||||
} else if (inputCounter === 2) {
|
||||
msg.payload.should.equal("Tail message line truncate");
|
||||
} else {
|
||||
msg.payload.should.equal("Tail message line append "+inputCounter);
|
||||
}
|
||||
|
||||
if (inputCounter === 5) {
|
||||
setTimeout(function() {
|
||||
warned.should.be.true();
|
||||
done();
|
||||
},100);
|
||||
}
|
||||
});
|
||||
var actions = [
|
||||
function() { fs.appendFileSync(fileToTail, "Tail message line append\n");},
|
||||
function() { fs.writeFileSync(fileToTail, "Tail message line truncate\n");},
|
||||
function() { fs.appendFileSync(fileToTail, "Tail message line append 3\n");},
|
||||
function() { fs.appendFileSync(fileToTail, "Tail message line append 4\n");},
|
||||
function() { fs.appendFileSync(fileToTail, "Tail message line append 5\n");}
|
||||
];
|
||||
|
||||
function processAction() {
|
||||
var action = actions.shift();
|
||||
action();
|
||||
if (actions.length > 0) {
|
||||
setTimeout(function() {
|
||||
processAction();
|
||||
},250);
|
||||
}
|
||||
}
|
||||
setTimeout( function() {
|
||||
processAction();
|
||||
},wait);
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
@ -59,8 +59,8 @@ describe("api/index", function() {
|
||||
afterEach(afterEach);
|
||||
|
||||
it("does not setup admin api if httpAdminRoot is false", function(done) {
|
||||
api.init({},{ httpAdminRoot: false },{},{});
|
||||
should.not.exist(api.adminApp);
|
||||
api.init({ httpAdminRoot: false },{},{},{});
|
||||
should.not.exist(api.httpAdmin);
|
||||
done();
|
||||
});
|
||||
describe('initalises admin api without adminAuth', function(done) {
|
||||
@ -70,30 +70,30 @@ describe("api/index", function() {
|
||||
});
|
||||
after(afterEach);
|
||||
it('exposes the editor',function(done) {
|
||||
request(api.adminApp).get("/editor").expect(200).end(done);
|
||||
request(api.httpAdmin).get("/editor").expect(200).end(done);
|
||||
})
|
||||
it('exposes the admin api',function(done) {
|
||||
request(api.adminApp).get("/admin").expect(200).end(done);
|
||||
request(api.httpAdmin).get("/admin").expect(200).end(done);
|
||||
})
|
||||
it('exposes the auth api',function(done) {
|
||||
request(api.adminApp).get("/auth/login").expect(200).end(done);
|
||||
request(api.httpAdmin).get("/auth/login").expect(200).end(done);
|
||||
})
|
||||
});
|
||||
|
||||
describe('initalises admin api without editor', function(done) {
|
||||
before(function() {
|
||||
beforeEach();
|
||||
api.init({},{ disableEditor: true },{},{});
|
||||
api.init({ disableEditor: true },{},{},{});
|
||||
});
|
||||
after(afterEach);
|
||||
it('does not expose the editor',function(done) {
|
||||
request(api.adminApp).get("/editor").expect(404).end(done);
|
||||
request(api.httpAdmin).get("/editor").expect(404).end(done);
|
||||
})
|
||||
it('exposes the admin api',function(done) {
|
||||
request(api.adminApp).get("/admin").expect(200).end(done);
|
||||
request(api.httpAdmin).get("/admin").expect(200).end(done);
|
||||
})
|
||||
it('exposes the auth api',function(done) {
|
||||
request(api.adminApp).get("/auth/login").expect(200).end(done)
|
||||
request(api.httpAdmin).get("/auth/login").expect(200).end(done)
|
||||
})
|
||||
});
|
||||
});
|
||||
|
20
test/unit/@node-red/registry/lib/util_spec.js
Normal file
20
test/unit/@node-red/registry/lib/util_spec.js
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
|
||||
describe("red/nodes/registry/util",function() {
|
||||
it.skip("NEEDS TESTS");
|
||||
});
|
@ -25,6 +25,8 @@ var runtime = NR_TEST_UTILS.require("@node-red/runtime");
|
||||
var redNodes = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes");
|
||||
var storage = NR_TEST_UTILS.require("@node-red/runtime/lib/storage");
|
||||
var settings = NR_TEST_UTILS.require("@node-red/runtime/lib/settings");
|
||||
var util = NR_TEST_UTILS.require("@node-red/util");
|
||||
|
||||
var log = NR_TEST_UTILS.require("@node-red/util").log;
|
||||
|
||||
describe("runtime", function() {
|
||||
@ -41,6 +43,7 @@ describe("runtime", function() {
|
||||
delete process.env.NODE_RED_HOME;
|
||||
});
|
||||
function mockUtil(metrics) {
|
||||
|
||||
return {
|
||||
log:{
|
||||
log: sinon.stub(),
|
||||
@ -95,6 +98,7 @@ describe("runtime", function() {
|
||||
var redNodesLoadFlows;
|
||||
var redNodesStartFlows;
|
||||
var redNodesLoadContextsPlugin;
|
||||
var i18nRegisterMessageCatalog;
|
||||
|
||||
beforeEach(function() {
|
||||
storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();});
|
||||
@ -104,6 +108,7 @@ describe("runtime", function() {
|
||||
redNodesLoadFlows = sinon.stub(redNodes,"loadFlows",function() {return Promise.resolve()});
|
||||
redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {});
|
||||
redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return Promise.resolve()});
|
||||
i18nRegisterMessageCatalog = sinon.stub(util.i18n,"registerMessageCatalog",function() {return Promise.resolve()});
|
||||
});
|
||||
afterEach(function() {
|
||||
storageInit.restore();
|
||||
@ -114,6 +119,7 @@ describe("runtime", function() {
|
||||
redNodesLoadFlows.restore();
|
||||
redNodesStartFlows.restore();
|
||||
redNodesLoadContextsPlugin.restore();
|
||||
i18nRegisterMessageCatalog.restore();
|
||||
});
|
||||
it("reports errored/missing modules",function(done) {
|
||||
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
|
||||
@ -199,10 +205,14 @@ describe("runtime", function() {
|
||||
var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} );
|
||||
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []});
|
||||
var util = mockUtil(true);
|
||||
runtime.init({testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util);
|
||||
sinon.stub(console,"log");
|
||||
runtime.init(
|
||||
{testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}},
|
||||
{},
|
||||
undefined,
|
||||
util);
|
||||
// sinon.stub(console,"log");
|
||||
runtime.start().then(function() {
|
||||
console.log.restore();
|
||||
// console.log.restore();
|
||||
setTimeout(function() {
|
||||
try {
|
||||
util.log.log.args.should.have.lengthOf(3);
|
||||
|
@ -31,31 +31,31 @@ var api = NR_TEST_UTILS.require("@node-red/runtime/lib/api");
|
||||
|
||||
describe("red/red", function() {
|
||||
|
||||
describe("check build", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(runtime,"init",function() {});
|
||||
sinon.stub(api,"init",function() {});
|
||||
sinon.stub(RED,"version",function() { return "version";});
|
||||
});
|
||||
afterEach(function() {
|
||||
runtime.init.restore();
|
||||
api.init.restore();
|
||||
fs.statSync.restore();
|
||||
RED.version.restore();
|
||||
});
|
||||
it.skip('warns if build has not been run',function() {
|
||||
sinon.stub(fs,"statSync",function() { throw new Error();});
|
||||
|
||||
/*jshint immed: false */
|
||||
(function() {
|
||||
RED.init({},{});
|
||||
}).should.throw("Node-RED not built");
|
||||
});
|
||||
it('passed if build has been run',function() {
|
||||
sinon.stub(fs,"statSync",function() { });
|
||||
RED.init({},{});
|
||||
});
|
||||
});
|
||||
// describe("check build", function() {
|
||||
// beforeEach(function() {
|
||||
// sinon.stub(runtime,"init",function() {});
|
||||
// sinon.stub(api,"init",function() {});
|
||||
// // sinon.stub(RED,"version",function() { return "version";});
|
||||
// });
|
||||
// afterEach(function() {
|
||||
// runtime.init.restore();
|
||||
// api.init.restore();
|
||||
// fs.statSync.restore();
|
||||
// // RED.version.restore();
|
||||
// });
|
||||
// it.skip('warns if build has not been run',function() {
|
||||
// sinon.stub(fs,"statSync",function() { throw new Error();});
|
||||
//
|
||||
// /*jshint immed: false */
|
||||
// (function() {
|
||||
// RED.init({},{});
|
||||
// }).should.throw("Node-RED not built");
|
||||
// });
|
||||
// it('passed if build has been run',function() {
|
||||
// sinon.stub(fs,"statSync",function() { });
|
||||
// RED.init({},{});
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("externals", function() {
|
||||
it('reports version', function() {
|
||||
|
Loading…
Reference in New Issue
Block a user