{"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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"}