diff --git a/Gruntfile.js b/Gruntfile.js index a11852854..907afd7ce 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -420,6 +420,13 @@ module.exports = function(grunt) { 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: { @@ -429,6 +436,13 @@ module.exports = function(grunt) { }, src: 'packages/node_modules/@node-red/runtime/lib/api/*.js', dest: 'docs/runtime-api.md' + }, + nodeREDUtil: { + options: { + separators: true + }, + src: 'packages/node_modules/@node-red/util/**/*.js', + dest: 'packages/node_modules/@node-red/util/docs/api.md' } } }); diff --git a/jsdoc.json b/jsdoc.json index 5ef3440a5..2a50b016a 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -1,6 +1,6 @@ { "opts": { - "template": "./node_modules/ink-docstrap/template", + "template": "./node_modules/minami", "destination": "./docs", "recurse": true }, @@ -9,7 +9,7 @@ "dictionaries": ["jsdoc"] }, "source": { - "include": [ + "_include": [ "./packages/node_modules/@node-red/runtime/lib/api" ] }, @@ -18,5 +18,6 @@ "theme":"yeti", "footer": "", "copyright": "Released under the Apache License v2.0" - } + }, + "plugins": ["plugins/markdown"] } diff --git a/package.json b/package.json index bdcf6e0d0..1e594e932 100644 --- a/package.json +++ b/package.json @@ -95,8 +95,8 @@ "grunt-simple-mocha": "~0.4.1", "grunt-webdriver": "^2.0.3", "http-proxy": "^1.16.2", - "ink-docstrap": "^1.3.2", "istanbul": "0.4.5", + "minami": "1.2.3", "mocha": "^5.2.0", "should": "^8.4.0", "sinon": "1.17.7", diff --git a/packages/node_modules/@node-red/util/index.js b/packages/node_modules/@node-red/util/index.js index f9640ba9b..f2804fedf 100644 --- a/packages/node_modules/@node-red/util/index.js +++ b/packages/node_modules/@node-red/util/index.js @@ -14,17 +14,26 @@ * limitations under the License. **/ - + /** + * @namespace @node-red/util + */ const log = require("./lib/log"); const i18n = require("./lib/i18n"); const util = require("./lib/util"); module.exports = { + /** + * Initialise the module with the runtime settings + * @param {Object} settings + */ init: function(settings) { log.init(settings); i18n.init(); }, log: log, i18n: i18n, + /** + * General utilities + */ util: util } diff --git a/packages/node_modules/@node-red/util/lib/i18n.js b/packages/node_modules/@node-red/util/lib/i18n.js index b92a25133..7d0f1ad92 100644 --- a/packages/node_modules/@node-red/util/lib/i18n.js +++ b/packages/node_modules/@node-red/util/lib/i18n.js @@ -12,6 +12,7 @@ * 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. + * @ignore **/ var i18n = require("i18next"); diff --git a/packages/node_modules/@node-red/util/lib/log.js b/packages/node_modules/@node-red/util/lib/log.js index 1925fd050..f3c66dd98 100644 --- a/packages/node_modules/@node-red/util/lib/log.js +++ b/packages/node_modules/@node-red/util/lib/log.js @@ -12,6 +12,7 @@ * 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. + * @ignore **/ var util = require("util"); diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js index d5643fcd5..ac777958f 100644 --- a/packages/node_modules/@node-red/util/lib/util.js +++ b/packages/node_modules/@node-red/util/lib/util.js @@ -12,17 +12,32 @@ * 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. + * @ignore **/ -var clone = require("clone"); -var jsonata = require("jsonata"); -var safeJSONStringify = require("json-stringify-safe"); -var util = require("util"); +const clone = require("clone"); +const jsonata = require("jsonata"); +const safeJSONStringify = require("json-stringify-safe"); +const util = require("util"); +/** + * Generates a psuedo-unique-random id. + * + * @return {String} a random-ish id + * @memberof @node-red/util.util + */ function generateId() { return (1+Math.random()*4294967295).toString(16); } +/** + * Converts the provided argument to a String, using type-dependent + * methods. + * + * @param {any} o - the property to convert to a String + * @return {String} the stringified version + * @memberof @node-red/util.util + */ function ensureString(o) { if (Buffer.isBuffer(o)) { return o.toString(); @@ -34,6 +49,14 @@ function ensureString(o) { return ""+o; } +/** + * Converts the provided argument to a Buffer, using type-dependent + * methods. + * + * @param {any} o - the property to convert to a Buffer + * @return {String} the Buffer version + * @memberof @node-red/util.util + */ function ensureBuffer(o) { if (Buffer.isBuffer(o)) { return o; @@ -45,6 +68,14 @@ function ensureBuffer(o) { return new Buffer(o); } +/** + * Safely clones a message object. This handles msg.req/msg.res objects that must + * not be cloned. + * + * @param {any} msg - the message object to clone + * @return {Object} the cloned message + * @memberof @node-red/util.util + */ function cloneMessage(msg) { // Temporary fix for #97 // TODO: remove this http-node-specific fix somehow @@ -64,6 +95,14 @@ function cloneMessage(msg) { return m; } +/** + * Compares two objects, handling various JavaScript types. + * + * @param {any} obj1 + * @param {any} obj2 + * @return {boolean} whether the two objects are the same + * @memberof @node-red/util.util + */ function compareObjects(obj1,obj2) { var i; if (obj1 === obj2) { @@ -130,6 +169,17 @@ function compareObjects(obj1,obj2) { return true; } +/** + * Parses a property expression, such as `msg.foo.bar[3]` to validate it + * and convert it to a canonical version expressed as an Array of property + * names. + * + * For example, `a["b"].c` returns `['a','b','c']` + * + * @param {String} str - the property expression + * @return {Array} the normalised expression + * @memberof @node-red/util.util + */ function normalisePropertyExpression(str) { // This must be kept in sync with validatePropertyExpression // in editor/js/ui/utils.js @@ -234,12 +284,32 @@ function normalisePropertyExpression(str) { return parts; } +/** + * Gets a property of a message object. + * + * Unlike {@link @node-red/util.util.getObjectProperty}, this function will strip `msg.` from the + * front of the property expression if present. + * + * @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 @node-red/util.util + */ function getMessageProperty(msg,expr) { if (expr.indexOf('msg.')===0) { expr = expr.substring(4); } return getObjectProperty(msg,expr); } + +/** + * Gets a property of an object. + * + * @param {Object} msg - the object + * @param {String} str - the property expression + * @return {any} the object property, or undefined if it does not exist + * @memberof @node-red/util.util + */ function getObjectProperty(msg,expr) { var result = null; var msgPropParts = normalisePropertyExpression(expr); @@ -251,12 +321,34 @@ function getObjectProperty(msg,expr) { return result; } +/** + * Sets a property of a message object. + * + * Unlike {@link @node-red/util.util.setObjectProperty}, this function will strip `msg.` from the + * front of the property expression if present. + * + * @param {Object} msg - the message object + * @param {String} prop - the property expression + * @param {any} value - the value to set + * @param {boolean} createMissing - whether to create missing parent properties + * @memberof @node-red/util.util + */ function setMessageProperty(msg,prop,value,createMissing) { if (prop.indexOf('msg.')===0) { prop = prop.substring(4); } return setObjectProperty(msg,prop,value,createMissing); } + +/** + * Sets a property of an object. + * + * @param {Object} msg - the object + * @param {String} prop - the property expression + * @param {any} value - the value to set + * @param {boolean} createMissing - whether to create missing parent properties + * @memberof @node-red/util.util + */ function setObjectProperty(msg,prop,value,createMissing) { if (typeof createMissing === 'undefined') { createMissing = (typeof value !== 'undefined'); @@ -311,6 +403,16 @@ function setObjectProperty(msg,prop,value,createMissing) { } } +/** + * Checks if a String contains any Environment Variable specifiers and returns + * it with their values substituted in place. + * + * For example, if the env var `WHO` is set to `Joe`, the string `Hello ${WHO}!` + * will return `Hello Joe!`. + * @param {String} value - the string to parse + * @return {String} The parsed string +* @memberof @node-red/util.util + */ function evaluateEnvProperty(value) { if (/^\${[^}]+}$/.test(value)) { // ${ENV_VAR} @@ -328,7 +430,18 @@ function evaluateEnvProperty(value) { return value; } -var parseContextStore = function(key) { + +/** + * Parses a context property string, as generated by the TypedInput, to extract + * the store name if present. + * + * For example, `#:(file)::foo` results in ` { store: "file", key: "foo" }`. + * + * @param {String} value - the context property string to parse + * @return {Object} The parsed property + * @memberof @node-red/util.util + */ +function parseContextStore(key) { var parts = {}; var m = /^#:\((\S+?)\)::(.*)$/.exec(key); if (m) { @@ -340,6 +453,18 @@ var parseContextStore = function(key) { return parts; } + +/** + * Evaluates a property value according to its type. + * + * @param {String} value - the raw value + * @param {String} type - the type of the value + * @param {Node} node - the node evaluating the property + * @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 @node-red/util.util + */ function evaluateNodeProperty(value, type, node, msg, callback) { var result = value; if (type === 'str') { @@ -387,6 +512,16 @@ function evaluateNodeProperty(value, type, node, msg, callback) { } } + +/** + * Prepares a JSONata expression for evaluation. + * This attaches Node-RED specific functions to the expression. + * + * @param {String} value - the JSONata expression + * @param {Node} node - the node evaluating the property + * @return {Object} The JSONata expression that can be evaluated + * @memberof @node-red/util.util + */ function prepareJSONataExpression(value,node) { var expr = jsonata(value); expr.assign('flowContext',function(val) { @@ -404,6 +539,17 @@ function prepareJSONataExpression(value,node) { return expr; } +/** + * Evaluates a JSONata expression. + * The expression must have been prepared with {@link @node-red/util.util.prepareJSONataExpression} + * before passing to this function. + * + * @param {Object} expr - the prepared JSONata expression + * @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 @node-red/util.util + */ function evaluateJSONataExpression(expr,msg,callback) { var context = msg; if (expr._legacyMode) { @@ -440,7 +586,15 @@ function evaluateJSONataExpression(expr,msg,callback) { return expr.evaluate(context, bindings, callback); } - +/** + * Normalise a node type name to camel case. + * + * For example: `a-random node type` will normalise to `aRandomNodeType` + * + * @param {String} name - the node type + * @return {String} The normalised name + * @memberof @node-red/util.util + */ function normaliseNodeTypeName(name) { var result = name.replace(/[^a-zA-Z0-9]/g, " "); result = result.trim(); @@ -454,6 +608,17 @@ function normaliseNodeTypeName(name) { return result; } +/** + * Encode an object to JSON without losing information about non-JSON types + * such as Buffer and Function. + * + * *This function is closely tied to its reverse within the editor* + * + * @param {Object} msg + * @param {Object} opts + * @return {Object} the encoded object + * @memberof @node-red/util.util + */ function encodeObject(msg,opts) { var debuglength = 1000; if (opts && opts.hasOwnProperty('maxLength')) { @@ -581,6 +746,11 @@ function encodeObject(msg,opts) { return msg; } +/** + * General utilities + * @namespace util + * @memberof @node-red/util + */ module.exports = { encodeObject: encodeObject, ensureString: ensureString,