Search code examples
javascriptnode.jscallbackgruntjsapiary.io

node.js - grunt - return parsed data from callback


I want to use API blueprint and make it automatically with grunt. I want to read apiary (tool for API blueprint) file, parsing it (with Protagonist which is API Blueprint Parser for Node.js), stringify it to the JSON format and write into another file. It is a simple task but I don't know how to do it, I always get undefined result. Here is what I have so far:

grunt.registerTask('apiary2js', 'Generate js version of apiary file.', function () {
    var parser = require('protagonist');
    var content = grunt.file.read('apiary.apib');
    var blueprint = parser.parse(content, function (error, result) {
        if (error) {
            console.log(error);
            return;
        }

        return result.ast; <-- (how to return this value?)
    });
    var json = JSON.stringify(blueprint);
    grunt.file.write('test/frontend/apiary.js', "var apiary = " + json);
});

And result in apiary.js is this:

var apiary = undefined

Solution

  • The problem you're running into is that the parser.parse() method accepts a callback which executes asynchronously. You can't return a value from a callback as you would in a synchronous method because you don't know when it will be executed. The solution is to place the 'return' logic in the callback.

    grunt.registerTask('apiary2js', 'Generate js version of apiary file.', function () {
        var parser = require('protagonist');
        var content = grunt.file.read('apiary.apib');
    
        // Parse the contents of the file & execute the callback when done parsing.
        parser.parse(content, function (error, result) {
    
            if (error) {
                console.log(error);
                return;
            }
    
            // Now we can use the result as desired.
            var json = JSON.stringify(result.ast);
            grunt.file.write('test/frontend/apiary.js', "var apiary = " + json);
        });
    
    });