Passing Clipboard to js.node shell script

I have a js.node script which successfully queries a MongoDb database.

An example of the relevant code for such a query is:

 var db = client.db("dt3_api");

    var collection = db.collection("LCP Production");
    
    var query = {
        "$and": [
            {
                "dt_kind": "Group"
            },
            {
                "dt_name": {
                    "$regex": "kaplan",
                    "$options": "i"
                }
            }
        ]
    };

I would like to pass the clipboard contents so I query that content rather than the literal word "kaplan". After some reading and review including some posts here in the past, I tried setting a variable to pbpaste to pass the clipboard into a variable and modified my script like this:

var Clip=$(pbpaste)

 var db = client.db("dt3_api");

    var collection = db.collection("LCP Production");
    
    var query = {
        "$and": [
            {
                "dt_kind": "Group"
            },
            {
                "dt_name": {
                    "$regex": Clip.toString(),
                    "$options": "i"
                }
            }
        ]
    };

The clipboard does get transferred correctly but I get this error from Node:

SyntaxError: Unexpected identifier
    at wrapSafe (internal/modules/cjs/loader.js:1072:16)
    at Module._compile (internal/modules/cjs/loader.js:1122:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
    at Module.load (internal/modules/cjs/loader.js:1002:32)
    at Function.Module._load (internal/modules/cjs/loader.js:901:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47
2021-09-02 18:05:57 Execute a Shell Script failed with script error: /privatetext-script:41
        function(doc) {Execute Shell Script
                               ^^^^^

SyntaxError: Unexpected identifier
    at wrapSafe (internal/modules/cjs/loader.js:1072:16)
    at Module._compile (internal/modules/cjs/loader.js:1122:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
    at Module.load (internal/modules/cjs/loader.js:1002:32)
    at Function.Module._load (internal/modules/cjs/loader.js:901:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47. Macro β€œTrying” cancelled (while executing Execute Shell Script).

Thoughts on how to revise the script here?

What is the Keyboard Maestro context here ?

You have pasted the Node.js code into an Execute Shell Script action ?

In order to comment, we would need to see at least the action, I think.

OK here is an image and technique which is more clear:

image

I am setting the KM variable Clip to the contents of the clipboard

The script is in Node with the shebang #! /usr/local/bin/Node

There is a version of the Node script (not shown) where I refer to:

"$regex":"Kaplan",

That original version of the Node script executes properly in KM to show me a window with the results of a search in my Mongo database containing the name Kaplan in a specific field.

But now I want to generalize this so it searches for whatever is in the clipboard instead of Kaplan.

So I have changed the above line to:

"$regex":$KMVar_Clip,

The result is this error in my KM Engine log:

So the bottom line is that Node is not recognizing the terminology $KMVar_Clip which I thought works to pass a KM variable to a shell script.

Does this notation only work with a shell script intended to run OS-level commands and not a shell script executed by Node? Is there an other way to pass the clipboard or a KM variable to Node?

I tried referencing $(pbpaste) instead of $KMVar_Clip and got the similar error "$ is not defined"

Could I ask you to attach a copy of the macro ?

We can't see the shell context of the node.js from a visual window into the middle of it – we need to see the framing and preamble, embedding and quoting, definition of search path, etc etc

Thanks

OK this is the full "Execute Shell Script" except with username:password for the database omitted:

#! /usr/local/bin/Node


var mongodb = require( '/Users/richardkaplan/node_modules/mongodb');



var BSONRegExp = mongodb.BSONRegExp;

var client = mongodb.MongoClient;


var limit=10;

var url = "mongodb://username:password@cluster0-shard-00-00.tt7vy.mongodb.net:27017,cluster0-shard-00-01.tt7vy.mongodb.net:27017,cluster0-shard-00-02.tt7vy.mongodb.net:27017/dt3_api?ssl=true&replicaSet=atlas-pogo5w-shard-0&authSource=admin&retryWrites=true&w=majority"

client.connect(url, function (err, client) {


 var db = client.db("dt3_api");

    var collection = db.collection("LCP Production");
    
    var query = {
        "$and": [
            {
                "dt_kind": "Group"
            },
            {
                "dt_name": {
                    "$regex":"Kaplan" ,
                    "$options": "i"
                }
            }
        ]
    };
    
    var cursor = collection.find(query).limit(limit);
    
    cursor.forEach(
        function(doc) {
            console.log(doc);
        }, 
        function(err) {
            client.close();
        }
    );
    
    // Created with Studio 3T, the IDE for MongoDB - https://studio3t.com/
    
});

There's a conflict there over which interpreter (the shell or the Node.js processor) interprets the status of the double quotes.

To allow the shell to unpack a $KMVAR_ reference, try for example, discarding the hash-bang prefixed:

#! /usr/local/bin/Node

in your the first line, (that's what we needed to see)
and using a Unix here-doc instead:

Use KMVar within Node.js.kmmacros (1.8 KB)

Interesting - your example works

But when I try this (keeping the hard-coded query and not even attempting the variable substitution yet) I get no response - no error, but no response either.

/usr/local/bin/Node <<NODE_END

require('/Users/richardkaplan/node_modules/console');

var  mongodb = require( '/Users/richardkaplan/node_modules/mongodb'); 



var BSONRegExp = mongodb.BSONRegExp;

var client = mongodb.MongoClient;


var limit=10;

var url = "mongodb://username:password@cluster0-shard-00-00.tt7vy.mongodb.net:27017,cluster0-shard-00-01.tt7vy.mongodb.net:27017,cluster0-shard-00-02.tt7vy.mongodb.net:27017/dt3_api?ssl=true&replicaSet=atlas-pogo5w-shard-0&authSource=admin&retryWrites=true&w=majority"

client.connect(url, function (err, client) {


 var db = client.db("dt3_api");

    var collection = db.collection("LCP Production");
    
    var query = {
        "$and": [
            {
                "dt_kind": "Group"
            },
            {
                "dt_name": {
                    "$regex":"Kaplan" ,
                    "$options": "i"
                }
            }
        ]
    };
    
    var cursor = collection.find(query).limit(limit);
    
    cursor.forEach(
        function(doc) {
            console.log(doc);
        }, 
        function(err) {
            client.close();
        }
    );
    
    // Created with Studio 3T, the IDE for MongoDB - https://studio3t.com/
    
});

NODE_END

The first thing I would try is to make sure that all the JS double quotes are switched to single quotes.

There is a contest here – pre-processing by the shell, followed by a second processing by Node and the JS interpreter itself. As JS is happy to back off from using the contended double quotes, you probably need to take advantage of that.

For example, given a string like "$regex" the shell phase will try to evaluate that as a shell variable. If regex is undefined in the shell, the result will be an empty string.

If '$regex' is a key which the JS interpreter should see, then you will need single rather than double quotes there, to forestall reduction by the shell phase.

OK - I did a search and replace and there are all single quotes now - still no error, no response at all to the script.

have you preserved double quotes around the KM var references ?

(you need double quotes wherever you want the shell to interpret a dollar-prefixed name)

As always, show often works, but tell never does – to make good use of our time and yours, you need to actually show us what you are doing : -)

PS if all you need from KM is the clipboard, then you may find it simpler to run your code directly in the shell, without KM variable expansion, bypassing the subtleties of multiple interpreter passes.

Clipboard text can be included with shell incantations like:

echo "$(pbpaste)"

Not yet- trying to get it working first with the literal string to be sure this idea works

I will try your idea of using shell tonight and report back - though if I do that I lose the ability to set a hotkey with KM. Would I accomplish the same goal by running it in KM as a file rather than keeping the script inside KM?

You won't get values for the KM names without the "$name" pattern.

Avoiding double quotes in the purely JS passages is required to avoid that transformation.

Understood - for now there aren't any KM variables - I was just trying to verify the script will run at all without the original Shebang - and it will not do so even with literals on the search string.

I will check out the idea of running it directly in Node with the pbpaste and get back to you tonight- much appreciated.

var query = {
        '$and': [
            {
                'dt_kind': 'Group'
            },
            {
                'dt_name': {
                    '$regex':'Kaplan' ,
                    '$options': 'i'
                }
            }
        ]
    };

OK - many thanks @ComplexPoint in working this through - the points you raised are nuances I never knew about script files

For reasons unclear to me I could not get pbpaste working with any of the configurations/uses we discussed.

I did solve the problem however. I found a Node.js module called clipboardy which will copy or paste to/from the system clipboard. The script now works (using the clipboard contents as part of the search criteria) when run in Node or in Keyboard Maestro or in TextExpander.

Again thanks for your help on this.

#! /usr/local/bin/Node



require('console');

var  mongodb = require( '/Users/richardkaplan/node_modules/mongodb');


const  clipboardy = require( '/Users/richardkaplan/node_modules/clipboardy');




var client = mongodb.MongoClient;


var limit=10;

var url = "mongodb://xxxxx:xxxxx@cluster0-shard-00-00.tt7vy.mongodb.net:27017,cluster0-shard-00-01.tt7vy.mongodb.net:27017,cluster0-shard-00-02.tt7vy.mongodb.net:27017/dt3_api?ssl=true&replicaSet=atlas-pogo5w-shard-0&authSource=admin&retryWrites=true&w=majority"

client.connect(url, function (err, client) {


 var db = client.db("dt3_api");

    var collection = db.collection("LCP Production");
    
    var query = {
        "$and": [
            {
                "dt_kind": "Group"
            },
            {
                "dt_name": {
                    "$regex":clipboardy.readSync() ,
                    "$options": "i"
                }
            }
        ]
    };
    
    var cursor = collection.find(query).limit(limit);
    
    cursor.forEach(
        function(doc) {
            console.log(doc);
        }, 
        function(err) {
            client.close();
        }
    );
    
    // Created with Studio 3T, the IDE for MongoDB - https://studio3t.com/
    
});
1 Like