Reputation: 920
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.
Upvotes: 1
Views: 249
Reputation: 1075855
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
});
Upvotes: 1