"Empty" is a judgement call, and the definition matters
There is no specification for what makes a JSON value empty, so every tool picks a rule. This one treats five things as empty: `null`, the empty string `""`, the empty array `[]`, the empty object `{}`, and containers that become empty once their own empty contents are removed. That last clause is what makes the operation recursive rather than a single pass.
Deliberately excluded are values that are falsy in JavaScript but carry real information. `0` is a number and usually a meaningful one - a count of zero, a price of zero, a temperature of zero. `false` is a definite answer, not a missing one. A string of one space is not the empty string. Treating any of these as empty is a classic source of data loss, because `if (!value)` in JavaScript is true for all of them.
That distinction is the main reason to prefer a tool with an explicit rule over a hand-written filter. Most quick filters written under time pressure use a falsy check and quietly delete every zero in the document.