ensurePluginsFolder = async () => {
  const rootFolder = envPaths("saltcorn", { suffix: "plugins" }).data;
  const staticDeps = ["@saltcorn/markup", "@saltcorn/data", "jest"];
  const allPluginFolders = new Set();
  await eachTenant(async () => {
    try {
      const allPlugins = (await Plugin.find()).filter(
        (p) => !["base", "sbadmin2"].includes(p.name)
      );
      for (const plugin of allPlugins) {
        const tokens =
          plugin.source === "npm"
            ? plugin.location.split("/")
            : plugin.name.split("/");
        const pluginDir = path.join(
          rootFolder,
          plugin.source === "git" ? "git_plugins" : "plugins_folder",
          ...tokens
        );
        allPluginFolders.add(pluginDir);
      }
    } catch {
      //ignore
    }
  });
  for (const folder of allPluginFolders) {
    try {
      if (pathExistsSync(folder)) {
        const packageJson = JSON.parse(
          readFileSync(path.join(folder, "package.json"))
        );
        if (
          (Object.keys(packageJson.dependencies || {}).some(
            (d) => !staticDeps.includes(d)
          ) ||
            Object.keys(packageJson.devDependencies || {}).some(
              (d) => !staticDeps.includes(d)
            )) &&
          !pathExistsSync(path.join(folder, "node_modules"))
        )
          rmdirSync(folder, { recursive: true });
      }
    } catch (e) {
      console.log(`Error checking plugin folder: ${e.message || e}`);
    }
  }
}
validate all plugins folders and remove invalid entries
A folder is invalid when it has dependencies but not node_modules directory