Process output from 'npm outdated' command

Hi Derek,

The flow is slightly dated now and there is another way to make node.js modules available to function nodes without having to share the require function in settings.js.

// End-of-line characters are different on each Operating System
// This uses Node.js features to get the right one but you
// can simply replace all of this with the appropriate string of control chars.
const require = global.get('require') // You have to add this to globals in settings.js
const EOL = require('os').EOL // OR just add `os.EOL` to settings.js instead and get that

Rather than the above from the original, make sure that you allow external modules in function nodes by changing the functionExternalModules property in settings.js to true and restarting nod-red.

Then you can simple reference the node.js built-in library os like this:

and change the function code to:

/**
 * Process the output from an `npm outdated` command.
 * Use msg.topic to allow different project folders to be tracked.
 * e.g. Global (`npm outdated -g`), 'user' for the Node-RED userDir, etc.
 */
 
// End-of-line characters are different on each Operating System
// This uses Node.js features to get the right one but you
// can simply replace all of this with the appropriate string of control chars.
const EOL = os.EOL

// Keep everything together - change this to flow or global if you want
const outdated = global.get('npm_outdated') || {}

// reset on each run - use the date entry if you want to track that
outdated[msg.topic] = {} // {updated: new Date()}

let out = outdated[msg.topic]
let heads = []

// Split the lines and process each one
msg.payload.split(EOL).forEach( (line,idx) => {
    // Don't do anything for empty lines
    if (line.length>0) {
        // Split the line by spaces, get rid of any entries that were just a space
        let tmp = line.split(' ').filter(e => e.length>0)
        
        if ( idx === 0 ) {
            // Track the headings that are on line 1
            heads = tmp
        } else {
            // Create an object for each package that needs updating
            out[tmp[0]] = {}
            tmp.forEach( (d,i) => {
                // and record the details
                out[tmp[0]][heads[i]] = d
            })
        }
    }
})

// Save - don't forget to change to global/flow if you change the get
global.set('npm_outdated', outdated)

return [
    // Output just this entry
    {
        topic: `npm/outdated/${msg.topic}`,
        parts: msg.parts,
        payload: out,
    },
    // Output everything
    {
        topic: `npm/outdated`,
        parts: msg.parts,
        payload: outdated,
    },
]

You should further note though that there are even easier ways to do all this. For example, simply use an exec node but make sure you include either --json or --parseable as an extra parameter, e.g. npm outdated -g --json and feed the output through a json node (--parseable creates a : separated list instead).