Jump to content

How to debug script filter that raises `JSON error: JSON text did not start with array or object and option to allow fragments not set`?


Recommended Posts

I have a js file that ends with 

 

msg = JSON.stringify(result)
$.NSFileHandle.fileHandleWithStandardOutput.writeData(
    $.NSString.alloc.initWithString(String(msg))
        .dataUsingEncoding($.NSUTF8StringEncoding)
)

 

When I run the script from the terminal, it returns JSON that appears to be correctly formatted for Script Filter. 

$ ~/Documents/myscript.js list
{"items":[{"uid":"1","title":"OptA","autocomplete":"OptA","subtitle":"OptA","arg":"1"},{"uid":"2","title":"OptB","autocomplete":"OptB","subtitle":"OptB","arg":"2"}]}

 

In Alfred, I created a workflow that contains a script filter. `Alfred filters results` is checked, language set to `bin/bash`, and it is configured to run my JS script:  

 

~/Documents/myscript.js list

 

When I type the keyword into Alfred, the workflow is displayed but no list results are returned. 

 

Alfred debugger returns 

 

ERROR: Script Filter to Script to Notification[Script Filter] JSON error: JSON text did not start with array or object and option to allow fragments not set. in JSON:
Error: Can't convert types.

 

I assume this means that whatever Alfred has received is not recognised as valid JSON, is this correct? 

 

Is there a way to interrogate Alfred to inspect what has been received into the script filter? 

 

Or is there a better way to debug this error?

 

Edited by astrofin
Link to comment
1 hour ago, astrofin said:

I assume this means that whatever Alfred has received is not recognised as valid JSON, is this correct?

 

Yes. The JSON is not valid. Going by what you’ve written, you have => at the beginning. If you set Alfred’s debugger to “All information”, it will also show the JSON.

 

In any case, you don’t need to mess about with Objective-C classes. You can just use return JSON.stringify(result) in your run() function.

Link to comment

Thanks deanishe, this has is very useful. 

 

I have modified my script to `return JSON.stringify(result)`. When I run the script in terminal, I'm now getting the same JSON that appears to be correctly formatted for Script Filter. 

 

$ ~/Documents/myscript.js list
{"items":[{"uid":"1","title":"OptA","autocomplete":"OptA","subtitle":"OptA","arg":"1"},{"uid":"2","title":"OptB","autocomplete":"OptB","subtitle":"OptB","arg":"2"}]}

 

However, I'm still getting the same error. 

 

I have tracked the source of this to the following line. I'm obtaining the data to populate the list from a csv file that is located in the same directory as script.js. 

const app = Application.currentApplication();
app.includeStandardAdditions = true

// path to the csv file 
var file = "list.csv";
    
// Read the file using a specific delimeter and return the results
var csv = app.read( Path(fileString) )

 

When I run this script in the terminal, the current application is able to read the csv. When I run this from Alfred, the script appears to fail at this point. 

 

What is the correct way to read the contents of text file? 

 

 

 

Edited by astrofin
Link to comment

Thanks deanishe, I appreciate your help with this. 

 

The following is a minimal version of the workflow that creates this issue. 

 

The workflow is very simple for testing purposes. It consists of only a Script Filter outputting to Large Type. The Script Filer runs my script.js file, which is not located within the workflow package because Alfred is not the only way I access it. The Script Filter script field contains only:

 

~/Documents/script.js list

 

~/Documents/script.js looks like this: 

#!/usr/bin/env osascript -l JavaScript
ObjC.import('stdlib')
ObjC.import('Foundation')
const app = Application.currentApplication();
app.includeStandardAdditions = true

function run(argv) {
    try {
        return selectCommand(argv)
    } catch (e) {
        return e
    }
}
function selectCommand(argv) { 
    const cmd = argv[0]
    if (cmd === 'list') {
        return list('all')
    }
    $.exit(0)
}
/**
 * Commands
 */
// Build the list 
function list() {
    
    // init an empty object to hold the results 
    var result = { 'items': [] }
    
    // the csv file 
    var file = "list.csv";
    // read the csv file
    var csv = app.read( Path(file) )
    // split the csv string into an array of rows
    var rows = csv.split('\r\n')
    // get the headers row 
    var headers = rows[0].split(',');
    
    // drop the header row 
    rows.splice(0,1)
    
    // iterate through the rows 
    rows.forEach( (row) => {
        // init an empty object to hold the results 
        var obj = {}
        // split the row into an array of attributes
        var currentRow = row.split(',')
        // iterate through the headers 
        headers.forEach( (header,i) => {
            // add the key/value pair to the obj container
            obj[header] = currentRow[i]
        })
        obj["autocomplete"] = obj["title"]
        obj["subtitle"]     = obj["title"]
        obj["arg"]          = obj["uid"]
        
        // push the current row object into the results array
        result.items.push(obj)
    })
    return JSON.stringify(result)
}

 

~/Documents/list.csv looks like this:

 

uid,title
1,OptA
2,OptB

 

Alfred debugger shows 

 

Error: Can't convert types. 
  message:Can't convert types., 
  errorNumber:-1700, 
  line:44, 
  column:23, 
  stack:[native code]

 

Line 44 is

var csv = app.read( Path(file) )

 

Is there a better way to read the file? 

Edited by astrofin
Link to comment
On 2/22/2021 at 1:04 AM, astrofin said:

When I run this script in the terminal, the current application is able to read the csv. When I run this from Alfred, the script appears to fail at this point.

 

Presumably because you’re telling it to read a file called list.csv in the current working directory, so the script will only work if run from the directory containing list.csv.

 

 

Either move list.csv (and script.js for that matter) into the workflow where the script is looking for it, or change the path in the script to an absolute one.

Link to comment

Thanks deanishe 

 

Can I please confirm that on your machine you're able to read `list.csv` if called from `script.js` using an absolute path? 

 

I've updated `script.js` to use `var file = "~/Documents/list.csv";`. It's still not working for me, which would suggest the problem lies elsewhere rather than with the script. 

 

It would be very useful if you're able to confirm this.

 

I note your suggestion to move everything into the workflow. For various reasons, `list.js` needs to be accessible outside the workflow, otherwise I would follow this suggestion. 

 

Thanks for taking the time to help!

Link to comment
55 minutes ago, astrofin said:

Can I please confirm that on your machine you're able to read `list.csv` if called from `script.js` using an absolute path?

 

I didn't change the script. I put both files inside the workflow, so they're both in the working directory when the workflow is run.

 

55 minutes ago, astrofin said:

var file = "~/Documents/list.csv";

 

That's not a valid path. ~ for your home directory only works in a shell. You need to write the full path (/Users/blah/Documents/...).

Link to comment

Thanks deanishe, appreciate your help with this. It's lead me to the right place. 

 

Thanks for confirming that the script works and the full path are required. I had tried full path previously, but there was also another issue preventing it working. 

 

I originally created list.csv from the terminal. I hadn't checked file permissions, which were very restrictive and preventing the script reading the file. 

 

I've set permissions to something more sensible, and the script now works. 

 

Thanks !

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...