How to use Turf mask when Polygon has islands in inner rings/inner rings

I am getting some weird result with turf.mask().

This is the polygon I am trying to run the mask() function with: https://gist.githubusercontent.com/Stophface/50155878441205412001247878f58b63/raw/324021868304f96c795e7d8cd18ec2c6f45ee842/polygon.geojson

According to the docs, if the mask is undefined, the world extent is used. The result of turf.mask(polygon, undefined) is this

So it is filling the interior ring Why is it doing that?

The data for the second code snippet of the accepted answere (because I deleted the original question) https://gist.github.com/Stophface/5f0cf7a28466d47f07c83d6d26eba078

• Definition of Turf.js mask method states that it "returns a polygon exterior ring with holes". What you want to have is "antihole" in a hole, which mask is not capable of. Such a polygon would be multipolygon, see stackoverflow.com/questions/74660981/…. Commented Feb 8, 2023 at 15:45
• @TomazicM Hm... Is there any way I can achieve that? Commented Feb 8, 2023 at 15:59

There might be simpler way of solving this problem by using some library, but one possible way with only Turf.js would be to:

• create array of outer liner rings and array of inner linear rings of polygon (with later reverse coordinate order);
• create multi polygon from outer linear rings and mask it;
• get linear rings of created masked polygon and append saved inner liner rings;
• create multi polygon from this array of rings.

Code could then look something like this:

var coords = turf.getCoords(polygon);

var outerRings = [];
var innerRings = [];

coords.forEach(function(polyCoords) {
polyCoords.forEach(function(linearRing, i) {
if (i == 0)
outerRings.push(linearRing);
else {
var poly = turf.rewind(turf.polygon([linearRing]));
innerRings.push(turf.getCoords(poly)[0]);
}
})
});
var outerRingsPoly = turf.multiPolygon([outerRings]);

var finalPoly = turf.multiPolygon([allRings]);

Result then looks like this:

EDIT: When testing again with GeoJSON with several holes, turf.js complained executing var coords = turf.getCoords(polygon), so I had to change logic a bit.

Here is modified code:

var outerRings = [];
var innerRings = [];

turf.geomEach(polygon, function(geom) {
geom.coordinates[0].forEach(function(linearRing, i) {
if (i == 0)
outerRings.push(linearRing);
else {
var poly = turf.rewind(turf.polygon([linearRing]));
innerRings.push(turf.getCoords(poly)[0]);
}
});
});

var outerRingsPoly = turf.multiPolygon([outerRings]);