{"version":3,"file":"dependencies.mjs","sources":["../../../../src/node/core/dependencies.ts"],"sourcesContent":["import os from 'node:os';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport semver, { SemVer } from 'semver';\nimport resolveFrom from 'resolve-from';\nimport execa, { CommonOptions, ExecaReturnValue } from 'execa';\nimport readPkgUp, { PackageJson } from 'read-pkg-up';\nimport type { BuildOptions } from '../build';\nimport { getPackageManager } from './managers';\n\n/**\n * From V5 this will be imported from the package.json of `@strapi/strapi`.\n */\nconst PEER_DEPS = {\n  react: '^18.0.0',\n  'react-dom': '^18.0.0',\n  'react-router-dom': '^6.0.0',\n  'styled-components': '^6.0.0',\n};\n\ninterface CheckRequiredDependenciesResult {\n  didInstall: boolean;\n}\n\ninterface DepToInstall {\n  name: string;\n  wantedVersion: string;\n  declaredVersion?: never;\n}\n\n/**\n * Checks the user's project that it has declared and installed the required dependencies\n * needed by the Strapi admin project. Whilst generally speaking most modules will be\n * declared by the actual packages there are some packages where you only really want one of\n * and thus they are declared as peer dependencies – react / styled-components / etc.\n *\n * If these deps are not installed or declared, then we prompt the user to correct this. In\n * V4 this is not a hard requirement, but in V5 it will be. Might as well get people started now.\n */\nconst checkRequiredDependencies = async ({\n  cwd,\n  logger,\n}: Pick<BuildOptions, 'cwd' | 'logger'>): Promise<CheckRequiredDependenciesResult> => {\n  /**\n   * This enables us to use experimental deps for libraries like\n   * react or styled-components. This is useful for testing against.\n   */\n  if (process.env.USE_EXPERIMENTAL_DEPENDENCIES === 'true') {\n    logger.warn('You are using experimental dependencies that may not be compatible with Strapi.');\n    return { didInstall: false };\n  }\n\n  const pkg = await readPkgUp({ cwd });\n\n  if (!pkg) {\n    throw new Error(`Could not find package.json at path: ${cwd}`);\n  }\n\n  logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);\n\n  interface DepToReview {\n    name: string;\n    wantedVersion: string;\n    declaredVersion: string;\n  }\n\n  /**\n   * Run through each of the peer deps and figure out if they need to be\n   * installed or they need their version checked against.\n   */\n  const { install, review } = Object.entries(PEER_DEPS).reduce<{\n    install: DepToInstall[];\n    review: DepToReview[];\n  }>(\n    (acc, [name, version]) => {\n      if (!pkg.packageJson.dependencies) {\n        throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);\n      }\n\n      const declaredVersion = pkg.packageJson.dependencies[name];\n\n      if (!declaredVersion) {\n        acc.install.push({\n          name,\n          wantedVersion: version,\n        });\n      } else {\n        acc.review.push({\n          name,\n          wantedVersion: version,\n          declaredVersion,\n        });\n      }\n\n      return acc;\n    },\n    {\n      install: [],\n      review: [],\n    }\n  );\n\n  if (install.length > 0) {\n    logger.info(\n      'The Strapi admin needs to install the following dependencies:',\n      os.EOL,\n      install.map(({ name, wantedVersion }) => `  - ${name}@${wantedVersion}`).join(os.EOL)\n    );\n\n    await installDependencies(install, {\n      cwd,\n      logger,\n    });\n\n    const [file, ...args] = process.argv;\n\n    /**\n     * Re-run the same command after installation e.g. strapi build because the yarn.lock might\n     * not be the same and could break installations. It's not the best solution, but it works.\n     */\n    await execa(file, args, { cwd, stdio: 'inherit' });\n    return { didInstall: true };\n  }\n\n  if (review.length) {\n    const errors: string[] = [];\n\n    for (const dep of review) {\n      // The version specified in package.json could be incorrect, eg `foo`\n      let minDeclaredVersion: SemVer | null = null;\n      try {\n        minDeclaredVersion = semver.minVersion(dep.declaredVersion);\n      } catch (err) {\n        // Intentional fall-through (variable will be left as null, throwing below)\n      }\n\n      if (!minDeclaredVersion) {\n        errors.push(\n          `The declared dependency, ${dep.name} has an invalid version in package.json: ${dep.declaredVersion}`\n        );\n      } else if (!semver.satisfies(minDeclaredVersion, dep.wantedVersion)) {\n        /**\n         * The delcared version should be semver compatible with our required version\n         * of the dependency. If it's not, we should advise the user to change it.\n         */\n        logger.warn(\n          [\n            `Declared version of ${dep.name} (${minDeclaredVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,\n            'You may experience issues, we recommend you change this.',\n          ].join(os.EOL)\n        );\n      }\n\n      const installedVersion = await getModuleVersion(dep.name, cwd);\n\n      if (!installedVersion) {\n        /**\n         * TODO: when we know the packageManager we can advise the actual install command.\n         */\n        errors.push(\n          `The declared dependency, ${dep.name} is not installed. You should install before re-running this command`\n        );\n      } else if (!semver.satisfies(installedVersion, dep.wantedVersion)) {\n        logger.warn(\n          [\n            `Declared version of ${dep.name} (${installedVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,\n            'You may experience issues, we recommend you change this.',\n          ].join(os.EOL)\n        );\n      }\n    }\n\n    if (errors.length > 0 && process.env.NODE_ENV === 'development') {\n      throw new Error(`${os.EOL}- ${errors.join(`${os.EOL}- `)}`);\n    }\n  }\n\n  return { didInstall: false };\n};\n\nconst getModule = async (name: string, cwd: string): Promise<PackageJson | null> => {\n  const modulePackagePath = resolveFrom.silent(cwd, path.join(name, 'package.json'));\n  if (!modulePackagePath) {\n    return null;\n  }\n  const file = await fs.readFile(modulePackagePath, 'utf8').then((res) => JSON.parse(res));\n\n  return file;\n};\n\nconst getModuleVersion = async (name: string, cwd: string): Promise<string | null> => {\n  const pkg = await getModule(name, cwd);\n\n  return pkg?.version || null;\n};\n\nconst installDependencies = async (\n  install: DepToInstall[],\n  { cwd, logger }: Pick<BuildOptions, 'cwd' | 'logger'>\n) => {\n  const packageManager = getPackageManager();\n\n  if (!packageManager) {\n    logger.error(\n      'Could not find a supported package manager, please install the dependencies manually.'\n    );\n    process.exit(1);\n  }\n\n  const execOptions: CommonOptions<'utf8'> = {\n    encoding: 'utf8',\n    cwd,\n    stdio: 'inherit',\n  };\n\n  const packages = install.map(({ name, wantedVersion }) => `${name}@${wantedVersion}`);\n\n  let result: ExecaReturnValue<string> | undefined;\n\n  if (packageManager === 'npm') {\n    const npmArgs = ['install', '--legacy-peer-deps', '--save', ...packages];\n    logger.info(`Running 'npm ${npmArgs.join(' ')}'`);\n    result = await execa('npm', npmArgs, execOptions);\n  } else if (packageManager === 'yarn') {\n    const yarnArgs = ['add', ...packages];\n    logger.info(`Running 'yarn ${yarnArgs.join(' ')}'`);\n    result = await execa('yarn', yarnArgs, execOptions);\n  } else if (packageManager === 'pnpm') {\n    const pnpmArgs = ['add', '--save-prod', ...packages];\n    logger.info(`Running 'pnpm ${pnpmArgs.join(' ')}'`);\n    result = await execa('pnpm', pnpmArgs, execOptions);\n  }\n\n  if (result?.exitCode || result?.failed) {\n    throw new Error('Package installation failed');\n  }\n};\n\nexport { checkRequiredDependencies, getModule };\nexport type { CheckRequiredDependenciesResult, PackageJson };\n"],"names":["PEER_DEPS","react","checkRequiredDependencies","cwd","logger","process","env","USE_EXPERIMENTAL_DEPENDENCIES","warn","didInstall","pkg","readPkgUp","Error","debug","os","EOL","packageJson","install","review","Object","entries","reduce","acc","name","version","dependencies","declaredVersion","push","wantedVersion","length","info","map","join","installDependencies","file","args","argv","execa","stdio","errors","dep","minDeclaredVersion","semver","minVersion","err","satisfies","installedVersion","getModuleVersion","NODE_ENV","getModule","modulePackagePath","resolveFrom","silent","path","fs","readFile","then","res","JSON","parse","packageManager","getPackageManager","error","exit","execOptions","encoding","packages","result","npmArgs","yarnArgs","pnpmArgs","exitCode","failed"],"mappings":"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"}