{"version":3,"file":"plugins.mjs","sources":["../../../../src/node/core/plugins.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport camelCase from 'lodash/camelCase';\nimport { env } from '@strapi/utils';\nimport { getModule, PackageJson } from './dependencies';\nimport { convertModulePathToSystemPath, convertSystemPathToModulePath, loadFile } from './files';\nimport type { BaseContext } from '../types';\nimport { isError } from './errors';\n\ninterface LocalPluginMeta {\n  name: string;\n  /**\n   * camelCased version of the plugin name\n   */\n  importName: string;\n  /**\n   * The path to the plugin, relative to the app's root directory\n   * in system format\n   */\n  path: string;\n  /**\n   * The path to the plugin, relative to the runtime directory\n   * in module format (i.e. with forward slashes) because thats\n   * where it should be used as an import\n   */\n  modulePath: string;\n  type: 'local';\n}\n\ninterface ModulePluginMeta {\n  name: string;\n  /**\n   * camelCased version of the plugin name\n   */\n  importName: string;\n  /**\n   * Modules don't have a path because we never resolve them to their node_modules\n   * because we simply do not require it.\n   */\n  path?: never;\n  /**\n   * The path to the plugin, relative to the app's root directory\n   * in module format (i.e. with forward slashes)\n   */\n  modulePath: string;\n  type: 'module';\n}\n\ntype PluginMeta = LocalPluginMeta | ModulePluginMeta;\n\ninterface StrapiPlugin extends PackageJson {\n  strapi: {\n    description?: string;\n    displayName?: string;\n    kind: 'plugin';\n    name?: string;\n    required?: boolean;\n  };\n}\n\nconst validatePackageHasStrapi = (\n  pkg: PackageJson\n): pkg is PackageJson & { strapi: Record<string, unknown> } =>\n  'strapi' in pkg &&\n  typeof pkg.strapi === 'object' &&\n  !Array.isArray(pkg.strapi) &&\n  pkg.strapi !== null;\n\nconst validatePackageIsPlugin = (pkg: PackageJson): pkg is StrapiPlugin =>\n  validatePackageHasStrapi(pkg) && pkg.strapi.kind === 'plugin';\n\nconst getEnabledPlugins = async ({\n  cwd,\n  logger,\n  runtimeDir,\n  strapi,\n}: Pick<BaseContext, 'cwd' | 'logger' | 'strapi' | 'runtimeDir'>): Promise<\n  Record<string, PluginMeta>\n> => {\n  const plugins: Record<string, PluginMeta> = {};\n\n  /**\n   * This is the list of dependencies that are installed in the user's project.\n   * It will include libraries like \"react\", so we need to collect the ones that\n   * are plugins.\n   */\n  const deps = strapi.config.get('info.dependencies', {});\n\n  logger.debug(\"Dependencies from user's project\", os.EOL, deps);\n\n  for (const dep of Object.keys(deps)) {\n    const pkg = await getModule(dep, cwd);\n\n    if (pkg && validatePackageIsPlugin(pkg)) {\n      const name = pkg.strapi.name || pkg.name;\n\n      if (!name) {\n        /**\n         * Unlikely to happen, but you never know.\n         */\n        throw Error(\n          \"You're trying to import a plugin that doesn't have a name – check the package.json of that plugin!\"\n        );\n      }\n\n      plugins[name] = {\n        name,\n        importName: camelCase(name),\n        type: 'module',\n        modulePath: dep,\n      };\n    }\n  }\n\n  const userPluginsFile = await loadUserPluginsFile(strapi.dirs.app.config);\n\n  logger.debug(\"User's plugins file\", os.EOL, userPluginsFile);\n\n  for (const [userPluginName, userPluginConfig] of Object.entries(userPluginsFile)) {\n    if (userPluginConfig.enabled && userPluginConfig.resolve) {\n      const sysPath = convertModulePathToSystemPath(userPluginConfig.resolve);\n      plugins[userPluginName] = {\n        name: userPluginName,\n        importName: camelCase(userPluginName),\n        type: 'local',\n        /**\n         * User plugin paths are resolved from the entry point\n         * of the app, because that's how you import them.\n         */\n        modulePath: convertSystemPathToModulePath(path.relative(runtimeDir, sysPath)),\n        path: sysPath,\n      };\n    }\n  }\n\n  return plugins;\n};\n\nconst PLUGIN_CONFIGS = ['plugins.js', 'plugins.mjs', 'plugins.ts'];\n\ntype UserPluginConfigFile = Record<string, { enabled: boolean; resolve: string }>;\n\nconst loadUserPluginsFile = async (root: string): Promise<UserPluginConfigFile> => {\n  for (const file of PLUGIN_CONFIGS) {\n    const filePath = path.join(root, file);\n    const configFile = await loadFile(filePath);\n\n    if (configFile) {\n      /**\n       * Configs can be a function or they can be just an object!\n       */\n      return typeof configFile === 'function' ? configFile({ env }) : configFile;\n    }\n  }\n\n  return {};\n};\n\nconst getMapOfPluginsWithAdmin = (plugins: Record<string, PluginMeta>) => {\n  /**\n   * This variable stores the import paths for plugins.\n   * The keys are the module paths of the plugins, and the values are the paths\n   * to the admin part of the plugins, which is either loaded from the\n   * package.json exports or from the legacy strapi-admin.js file.\n   */\n  const pluginImportPaths: Record<string, string> = {};\n\n  return Object.values(plugins)\n    .filter((plugin) => {\n      if (!plugin) {\n        return false;\n      }\n\n      /**\n       * There are two ways a plugin should be imported, either it's local to the strapi app,\n       * or it's an actual npm module that's installed and resolved via node_modules.\n       *\n       * We first check if the plugin is local to the strapi app, using a regular `fs.existsSync` because\n       * the pathToPlugin will be relative i.e. `/Users/my-name/strapi-app/src/plugins/my-plugin`.\n       *\n       * If the file doesn't exist well then it's probably a node_module, so instead we use `require.resolve`\n       * which will resolve the path to the module in node_modules. If it fails with the specific code `MODULE_NOT_FOUND`\n       * then it doesn't have an admin part to the package.\n       */\n      try {\n        const localPluginPath = plugin.path;\n        if (localPluginPath) {\n          // Here we are loading a locally installed plugin\n          const packageJsonPath = path.join(localPluginPath, 'package.json');\n\n          if (fs.existsSync(packageJsonPath)) {\n            const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n            const localAdminPath = packageJson?.exports?.['./strapi-admin']?.import;\n\n            if (localAdminPath) {\n              pluginImportPaths[plugin.modulePath] = localAdminPath;\n              return true;\n            }\n          }\n\n          // Check if legacy admin file exists in local plugin\n          if (fs.existsSync(path.join(localPluginPath, 'strapi-admin.js'))) {\n            pluginImportPaths[plugin.modulePath] = 'strapi-admin';\n            return true;\n          }\n        }\n\n        // This plugin is a module, so we need to check if it has a strapi-admin export\n        if (require.resolve(`${plugin.modulePath}/strapi-admin`)) {\n          pluginImportPaths[plugin.modulePath] = 'strapi-admin';\n          return true;\n        }\n\n        return false;\n      } catch (err) {\n        if (\n          isError(err) &&\n          'code' in err &&\n          (err.code === 'MODULE_NOT_FOUND' || err.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')\n        ) {\n          /**\n           * the plugin does not contain FE code, so we\n           * don't want to import it anyway\n           */\n          return false;\n        }\n\n        throw err;\n      }\n    })\n    .map((plugin) => ({\n      ...plugin,\n      modulePath: `${plugin.modulePath}/${pluginImportPaths[plugin.modulePath]}`,\n    }));\n};\n\nexport { getEnabledPlugins, getMapOfPluginsWithAdmin };\nexport type { PluginMeta, LocalPluginMeta, ModulePluginMeta };\n"],"names":["validatePackageHasStrapi","pkg","strapi","Array","isArray","validatePackageIsPlugin","kind","getEnabledPlugins","cwd","logger","runtimeDir","plugins","deps","config","get","debug","os","EOL","dep","Object","keys","getModule","name","Error","importName","camelCase","type","modulePath","userPluginsFile","loadUserPluginsFile","dirs","app","userPluginName","userPluginConfig","entries","enabled","resolve","sysPath","convertModulePathToSystemPath","convertSystemPathToModulePath","path","relative","PLUGIN_CONFIGS","root","file","filePath","join","configFile","loadFile","env","getMapOfPluginsWithAdmin","pluginImportPaths","values","filter","plugin","localPluginPath","packageJsonPath","fs","existsSync","packageJson","JSON","parse","readFileSync","localAdminPath","exports","import","require","err","isError","code","map"],"mappings":"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"}