Module everything

./lua/module everything.lua
/silent-command --[[ module everything --]]
local function box_on_surface(s)
  local a,b,c,d,m,M,n=1/0,1/0,-1/0,-1/0,math.min,math.max
  for x,y,z in s:gmatch("%[gps=([+-]?[%d%.]+),([+-]?[%d%.]+),?([^%]]*)%]")do a=m(a,x+0)b=m(b,y+0)c=M(c,x+0)d=M(d,y+0)n=z end
  return{left_top={x=a,y=b},right_bottom={x=c,y=d}}, game.get_surface(#n>0 and n or 1)
end
local function proxy_for(e)
  return e.surface.find_entity("item-request-proxy", e.position)
end
--[[ allowed[module][recipe] + caches result --]]
local allowed = setmetatable({}, {
  __index = function(mytable, module_name)
    local table_of_allowed = {}
    for _,allowed_recipe in pairs(game.item_prototypes[module_name].limitations) do
      table_of_allowed[allowed_recipe] = true
    end
    rawset(mytable, module_name, table_of_allowed)
    return table_of_allowed
  end
})
local function add_to(t, add_me)
  for k,v in pairs(add_me) do
    t[k] = (t[k] or 0) + v
  end
end
local function total_count(t)
  local total = 0
  for _,v in pairs(t) do
    total = total + v
  end
  return total
end
local function speed_if_cant_prod(recipe, modules)
  local substitutes = {}
  for mod,_ in pairs(modules) do
    if not allowed[mod][recipe] then
      local n = modules[mod]
      modules[mod] = nil
      local substitute_mod = mod:gsub("productivity%-", "speed-")
      if substitute_mod == mod then
        substitute_mod = "speed-module"
      end
      substitutes[substitute_mod] = (substitutes[substitute_mod] or 0) + n
    end
  end
  add_to(modules, substitutes)
end
local function main(types_to_mod, gps)
  local n_modules, n_machines, types_for_search = 0,0,{}
  for typename,_ in pairs(types_to_mod) do
    table.insert(types_for_search, typename)
  end
  local box, surface = box_on_surface(gps)
  for _,e in pairs(surface.find_entities_filtered{area=box,type=types_for_search}) do
    local totals = {}
    local mod_inv = e.get_module_inventory()
    add_to(totals, mod_inv.get_contents())
    local req = proxy_for(e)
    if req then
      add_to(totals, req.item_requests)
    end
    local unused = #mod_inv - total_count(totals)
    if unused > 0 then
      local new_reqs = { [types_to_mod[e.type]] = unused }
      if e.prototype.crafting_categories and e.get_recipe() then
        speed_if_cant_prod(e.get_recipe().name, new_reqs)
      end
      if req then
        add_to(new_reqs, req.item_requests)
        req.item_requests = new_reqs
      else
        e.surface.create_entity{name="item-request-proxy", position=e.position, force=e.force, target=e, modules=new_reqs}
      end
      n_modules = n_modules + unused
      n_machines = n_machines + 1
    end
  end
  --[[ again, for ghosts --]]
  for _,e in pairs(surface.find_entities_filtered{area=box,ghost_type=types_for_search}) do
    local unused = e.ghost_prototype.module_inventory_size - total_count(e.item_requests)
    if unused > 0 then
      local new_reqs = { [types_to_mod[e.ghost_type]] = unused }
      if e.ghost_prototype.crafting_categories and e.get_recipe() then
        speed_if_cant_prod(e.get_recipe().name, new_reqs)
      end
      add_to(new_reqs, e.item_requests)
      e.item_requests = new_reqs
      n_modules = n_modules + unused
      n_machines = n_machines + 1
    end
  end
  game.print(string.format("Requesting %d modules in %d machines.", n_modules, n_machines))
end
local function go(gps) main({
  ["assembling-machine"]="productivity-module",
  furnace="productivity-module",
  beacon="speed-module",
  ["mining-drill"]="effectivity-module"
}, gps) end
go "