I should preface all of this with the below applies to magento 2.3, possibly 2.x and up... I am working on 2.3 at the moment...
I am still trying to grapple with repositories and factories, all the code above or that i can find regarding this does not use either repositories or factories, and this seems to still be an issue even in magento 2.3 so what I did was two lines in mysql you may have to modify if you have more than one store... first it is much easier to just disable all categories and then enable any category that has any products, than the other way around, so one line to disable all categories in tree on frontend in mysql shell or phpmyadmin...
update catalog_category_entity_int set catalog_category_entity_int.value = 0 where catalog_category_entity_int.store_id = 0 and catalog_category_entity_int.attribute_id = (select attribute_id from eav_attribute where attribute_code = 'include_in_menu') or catalog_category_entity_int.attribute_id = (select attribute_id from eav_attribute where attribute_code = 'is_active');
then turn active and include in menu any categories that have any products in stock with
update catalog_category_entity_int left join catalog_category_product on catalog_category_product.category_id = catalog_category_entity_int.entity_id left join cataloginventory_stock_item on cataloginventory_stock_item.product_id = catalog_category_product.product_id set catalog_category_entity_int.value = 1 where catalog_category_entity_int.store_id = 0 and cataloginventory_stock_item.qty > 0 and catalog_category_entity_int.attribute_id = (select attribute_id from eav_attribute where attribute_code = 'include_in_menu') or cataloginventory_stock_item.qty > 0 and catalog_category_entity_int.attribute_id = (select attribute_id from eav_attribute where attribute_code = 'is_active');
there is an extension somewhere that has not been updated for the newer magento, that someone experienced issues with from this stackexchange here https://magento.stackexchange.com/questions/36/hide-categories-with-no-active-products
two lines is simple and could even be made into a procedure.
this by no means should be a final solution, but should get the job done until this sort of thing is built into the core... one shouldn't have to code an extension for something simple like this...