1

In short: I have a callback function that has a string parameter and has to return a string. I need to transform this string using a library that only works with streams. How do I do it?

Longer: I'm using Node.js replacestream which has a feature to match RegEx and just like String.replace it allows to specify a callback function for replacing. What I need to do, is take the matched string, run it through another library, and then return the transformed string for replace.

The problem is that this library only works with streams. Normally I could make the entire thing asynchronous but I don't see any way to do it with String.replace callback.

src(['*.js'])
.pipe(replace(/`(.*?)`/gs, function(match, p1, offset, string) {
    var ostream = stringtostream(p1);
    ostream.pipe(glslminify());

    //???code that waits for ostream to finish and converts it to string???

    return string_from_ostream;
}))
.pipe(dest(jsdest));

There must be a better way to do this, so I'm looking for any suggestions.

3
  • 1
    This library: github.com/TimvanScherpenzeel/glsl-minifier Commented Sep 25, 2020 at 6:56
  • 1
    I'm looking... It consists of 4 different sub-libraries and at least 2 of them has a way to do it synchronously, so this would completely solve my issue if all 4 of them can do it. Commented Sep 25, 2020 at 7:02
  • Unfortunately this one seems to be asynchronous: npmjs.com/package/glsl-min-stream Commented Sep 25, 2020 at 7:05

1 Answer 1

1

You'd clarified that the library uses a stream and, importantly, does its work asynchronously. That means you can't use it directly in a replace callback to determine the callback's return value, since of course that has to be provided synchronously.

What you can do instead is make your function asynchronous, break the string up into the parts that need processing and the parts that don't, trigger the asynchronous processing of the parts that need processing, then assemble the completed string when those are done.

Here's an example using a stand-in asynchronous process that reports completion via promises (you can wrap a promise around the stream, or adapt the code to use stream completion instead):

// Your function for processing the string
function yourFunction(str) {
    return Promise.all(
        str.split(/`(.*?)`/s).map((fragment, index) =>
            // The capture groups are the odd-numbered indexes
            index % 2 === 1
            ? process(fragment)
            : fragment
        )
    )
    .then(segments => segments.join(""));
}

// The promise wrapper around the library
function process(str) {
    return new Promise((resolve, reject) => {
        // Emulate via timer; I'm not emulating failure here, but
        // you'd handle failure by calling `reject`
        setTimeout(() => {
            // Success
            resolve(str.toUpperCase());
        }, Math.random() * 400);
    });
}

// Testing with and without leading and trailing text
yourFunction("`one two three` testing `two three four`")
.then(result => {
    console.log(result);
    return yourFunction("leading text `one two three` testing `two three four`")
})
.then(result => {
    console.log(result);
    return yourFunction("leading text `one two three` testing `two three four` trailing text")
})
.then(result => {
    console.log(result);
})
.catch(error => {
    // Handle/report error
});

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, let me try to adapt this to my particular situation and after that I'll checkmark the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.