@strapi/strapi 5.47.1 → 5.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +9 -9
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/develop.d.ts.map +1 -1
  4. package/dist/node/build.d.ts +7 -1
  5. package/dist/node/build.d.ts.map +1 -1
  6. package/dist/node/core/dependencies.d.ts +35 -13
  7. package/dist/node/core/dependencies.d.ts.map +1 -1
  8. package/dist/node/core/ensure-admin-dependencies.d.ts +25 -0
  9. package/dist/node/core/ensure-admin-dependencies.d.ts.map +1 -0
  10. package/dist/node/core/plugins.d.ts.map +1 -1
  11. package/dist/node/develop.d.ts +7 -1
  12. package/dist/node/develop.d.ts.map +1 -1
  13. package/dist/node/vite/config.d.ts.map +1 -1
  14. package/dist/node/webpack/config.d.ts.map +1 -1
  15. package/dist/package.json.js +1 -1
  16. package/dist/package.json.mjs +1 -1
  17. package/dist/src/cli/commands/build.js +1 -1
  18. package/dist/src/cli/commands/build.js.map +1 -1
  19. package/dist/src/cli/commands/build.mjs +1 -1
  20. package/dist/src/cli/commands/build.mjs.map +1 -1
  21. package/dist/src/cli/commands/develop.js +1 -1
  22. package/dist/src/cli/commands/develop.js.map +1 -1
  23. package/dist/src/cli/commands/develop.mjs +1 -1
  24. package/dist/src/cli/commands/develop.mjs.map +1 -1
  25. package/dist/src/node/build.js +6 -8
  26. package/dist/src/node/build.js.map +1 -1
  27. package/dist/src/node/build.mjs +6 -8
  28. package/dist/src/node/build.mjs.map +1 -1
  29. package/dist/src/node/core/dependencies.js +115 -118
  30. package/dist/src/node/core/dependencies.js.map +1 -1
  31. package/dist/src/node/core/dependencies.mjs +105 -118
  32. package/dist/src/node/core/dependencies.mjs.map +1 -1
  33. package/dist/src/node/core/ensure-admin-dependencies.js +70 -0
  34. package/dist/src/node/core/ensure-admin-dependencies.js.map +1 -0
  35. package/dist/src/node/core/ensure-admin-dependencies.mjs +67 -0
  36. package/dist/src/node/core/ensure-admin-dependencies.mjs.map +1 -0
  37. package/dist/src/node/core/plugins.js +19 -3
  38. package/dist/src/node/core/plugins.js.map +1 -1
  39. package/dist/src/node/core/plugins.mjs +19 -3
  40. package/dist/src/node/core/plugins.mjs.map +1 -1
  41. package/dist/src/node/develop.js +6 -8
  42. package/dist/src/node/develop.js.map +1 -1
  43. package/dist/src/node/develop.mjs +6 -8
  44. package/dist/src/node/develop.mjs.map +1 -1
  45. package/dist/src/node/vite/config.js +9 -2
  46. package/dist/src/node/vite/config.js.map +1 -1
  47. package/dist/src/node/vite/config.mjs +9 -2
  48. package/dist/src/node/vite/config.mjs.map +1 -1
  49. package/dist/src/node/webpack/config.js +2 -1
  50. package/dist/src/node/webpack/config.js.map +1 -1
  51. package/dist/src/node/webpack/config.mjs +2 -1
  52. package/dist/src/node/webpack/config.mjs.map +1 -1
  53. package/package.json +26 -26
@@ -32,149 +32,114 @@ const writeCachedHash = async (cwd, hash)=>{
32
32
  };
33
33
  /**
34
34
  * From V5 this will be imported from the package.json of `@strapi/strapi`.
35
- */ const PEER_DEPS = {
35
+ */ const ADMIN_PEER_DEPS = {
36
36
  react: '^18.0.0',
37
37
  'react-dom': '^18.0.0',
38
38
  'react-router-dom': '^6.0.0',
39
39
  'styled-components': '^6.0.0'
40
40
  };
41
- /**
42
- * Checks the user's project that it has declared and installed the required dependencies
43
- * needed by the Strapi admin project. Whilst generally speaking most modules will be
44
- * declared by the actual packages there are some packages where you only really want one of
45
- * and thus they are declared as peer dependencies – react / styled-components / etc.
46
- *
47
- * If these deps are not installed or declared, then we prompt the user to correct this. In
48
- * V4 this is not a hard requirement, but in V5 it will be. Might as well get people started now.
49
- */ const checkRequiredDependencies = async ({ cwd, logger })=>{
50
- /**
51
- * This enables us to use experimental deps for libraries like
52
- * react or styled-components. This is useful for testing against.
53
- */ if (process.env.USE_EXPERIMENTAL_DEPENDENCIES === 'true') {
54
- logger.warn('You are using experimental dependencies that may not be compatible with Strapi.');
55
- return {
56
- didInstall: false
57
- };
58
- }
59
- // Hash-cache: skip the full check when package.json hasn't changed since
60
- // the last successful pass. The cache lives under node_modules so it's
61
- // already gitignored and disposable (a `yarn install` wipe re-runs it).
62
- const currentHash = await hashPackageJson(cwd);
63
- if (currentHash) {
64
- const cachedHash = await readCachedHash(cwd);
65
- if (cachedHash === currentHash) {
66
- return {
67
- didInstall: false
68
- };
69
- }
41
+ class MissingAdminPeerDepsError extends Error {
42
+ constructor(missing){
43
+ super('Missing required dependencies. Please install them and re-run this command.');
44
+ this.name = 'MissingAdminPeerDepsError';
45
+ this.missing = missing;
70
46
  }
47
+ }
48
+ const loadProjectPackageJson = async (cwd)=>{
71
49
  const pkg = await readPkgUp({
72
50
  cwd
73
51
  });
74
52
  if (!pkg) {
75
53
  throw new Error(`Could not find package.json at path: ${cwd}`);
76
54
  }
77
- logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);
78
- /**
79
- * Run through each of the peer deps and figure out if they need to be
80
- * installed or they need their version checked against.
81
- */ const { install, review } = Object.entries(PEER_DEPS).reduce((acc, [name, version])=>{
82
- if (!pkg.packageJson.dependencies) {
83
- throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);
84
- }
85
- const declaredVersion = pkg.packageJson.dependencies[name] ?? pkg.packageJson.devDependencies?.[name];
55
+ if (!pkg.packageJson.dependencies) {
56
+ throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);
57
+ }
58
+ return pkg;
59
+ };
60
+ /**
61
+ * Returns admin peer dependencies that are not declared in the project's package.json.
62
+ */ const findUndeclaredAdminPeerDeps = async (cwd)=>{
63
+ const pkg = await loadProjectPackageJson(cwd);
64
+ return Object.entries(ADMIN_PEER_DEPS).reduce((missing, [name, version])=>{
65
+ const declaredVersion = pkg.packageJson.dependencies?.[name] ?? pkg.packageJson.devDependencies?.[name];
86
66
  if (!declaredVersion) {
87
- acc.install.push({
67
+ missing.push({
88
68
  name,
89
69
  wantedVersion: version
90
70
  });
91
- } else {
92
- acc.review.push({
71
+ }
72
+ return missing;
73
+ }, []);
74
+ };
75
+ const getDeclaredAdminPeerDeps = (packageJson)=>{
76
+ return Object.entries(ADMIN_PEER_DEPS).reduce((declared, [name, version])=>{
77
+ const declaredVersion = packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name];
78
+ if (declaredVersion) {
79
+ declared.push({
93
80
  name,
94
81
  wantedVersion: version,
95
82
  declaredVersion
96
83
  });
97
84
  }
98
- return acc;
99
- }, {
100
- install: [],
101
- review: []
102
- });
103
- if (install.length > 0) {
104
- logger.info('The Strapi admin needs to install the following dependencies:', os.EOL, install.map(({ name, wantedVersion })=>` - ${name}@${wantedVersion}`).join(os.EOL));
105
- await installDependencies(install, {
106
- cwd,
107
- logger
108
- });
109
- const [file, ...args] = process.argv;
110
- /**
111
- * Re-run the same command after installation e.g. strapi build because the yarn.lock might
112
- * not be the same and could break installations. It's not the best solution, but it works.
113
- */ await execa(file, args, {
114
- cwd,
115
- stdio: 'inherit'
116
- });
117
- return {
118
- didInstall: true
119
- };
85
+ return declared;
86
+ }, []);
87
+ };
88
+ const getInstallCommandHint = (missing)=>{
89
+ const packages = missing.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`).join(' ');
90
+ const packageManager = managers.getPackageManager();
91
+ if (packageManager === 'yarn') {
92
+ return `yarn add ${packages}`;
93
+ }
94
+ if (packageManager === 'pnpm') {
95
+ return `pnpm add --save-prod ${packages}`;
120
96
  }
121
- if (review.length) {
122
- const errors = [];
123
- for (const dep of review){
124
- // The version specified in package.json could be incorrect, eg `foo`
125
- let minDeclaredVersion = null;
126
- try {
127
- minDeclaredVersion = semver.minVersion(dep.declaredVersion);
128
- } catch (err) {
129
- // Intentional fall-through (variable will be left as null, throwing below)
130
- }
131
- if (!minDeclaredVersion) {
132
- errors.push(`The declared dependency, ${dep.name} has an invalid version in package.json: ${dep.declaredVersion}`);
133
- } else if (!semver.satisfies(minDeclaredVersion, dep.wantedVersion)) {
134
- /**
135
- * The delcared version should be semver compatible with our required version
136
- * of the dependency. If it's not, we should advise the user to change it.
137
- */ logger.warn([
138
- `Declared version of ${dep.name} (${minDeclaredVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
139
- 'You may experience issues, we recommend you change this.'
140
- ].join(os.EOL));
141
- }
142
- const installedVersion = await getModuleVersion(dep.name, cwd);
143
- if (!installedVersion) {
144
- /**
145
- * TODO: when we know the packageManager we can advise the actual install command.
146
- */ errors.push(`The declared dependency, ${dep.name} is not installed. You should install before re-running this command`);
147
- } else if (!semver.satisfies(installedVersion, dep.wantedVersion)) {
148
- logger.warn([
149
- `Declared version of ${dep.name} (${installedVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
150
- 'You may experience issues, we recommend you change this.'
151
- ].join(os.EOL));
152
- }
97
+ return `npm install --legacy-peer-deps --save ${packages}`;
98
+ };
99
+ const reportMissingAdminPeerDeps = (logger, missing)=>{
100
+ logger.error('The Strapi admin is missing required dependencies:', os.EOL, missing.map(({ name, wantedVersion })=>` - ${name}@${wantedVersion}`).join(os.EOL));
101
+ logger.error('Please install them manually before re-running this command:', os.EOL, ` ${getInstallCommandHint(missing)}`);
102
+ };
103
+ /**
104
+ * Validates declared admin peer dependencies (versions and node_modules presence).
105
+ */ const validateDeclaredAdminPeerDeps = async (cwd, logger)=>{
106
+ const pkg = await loadProjectPackageJson(cwd);
107
+ const declared = getDeclaredAdminPeerDeps(pkg.packageJson);
108
+ if (!declared.length) {
109
+ return;
110
+ }
111
+ logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);
112
+ const errors = [];
113
+ for (const dep of declared){
114
+ let minDeclaredVersion = null;
115
+ try {
116
+ minDeclaredVersion = semver.minVersion(dep.declaredVersion);
117
+ } catch (err) {
118
+ // Intentional fall-through (variable will be left as null, throwing below)
153
119
  }
154
- if (errors.length > 0 && process.env.NODE_ENV === 'development') {
155
- throw new Error(`${os.EOL}- ${errors.join(`${os.EOL}- `)}`);
120
+ if (!minDeclaredVersion) {
121
+ errors.push(`The declared dependency, ${dep.name} has an invalid version in package.json: ${dep.declaredVersion}`);
122
+ } else if (!semver.satisfies(minDeclaredVersion, dep.wantedVersion)) {
123
+ logger.warn([
124
+ `Declared version of ${dep.name} (${minDeclaredVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
125
+ 'You may experience issues, we recommend you change this.'
126
+ ].join(os.EOL));
127
+ }
128
+ const installedVersion = await getModuleVersion(dep.name, cwd);
129
+ if (!installedVersion) {
130
+ errors.push(`The declared dependency, ${dep.name} is not installed. You should install before re-running this command`);
131
+ } else if (!semver.satisfies(installedVersion, dep.wantedVersion)) {
132
+ logger.warn([
133
+ `Declared version of ${dep.name} (${installedVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
134
+ 'You may experience issues, we recommend you change this.'
135
+ ].join(os.EOL));
156
136
  }
157
137
  }
158
- if (currentHash) {
159
- await writeCachedHash(cwd, currentHash);
160
- }
161
- return {
162
- didInstall: false
163
- };
164
- };
165
- const getModule = async (name, cwd)=>{
166
- const modulePackagePath = resolveFrom.silent(cwd, path.join(name, 'package.json'));
167
- if (!modulePackagePath) {
168
- return null;
138
+ if (errors.length > 0 && process.env.NODE_ENV === 'development') {
139
+ throw new Error(`${os.EOL}- ${errors.join(`${os.EOL}- `)}`);
169
140
  }
170
- const file = await fs.readFile(modulePackagePath, 'utf8').then((res)=>JSON.parse(res));
171
- return file;
172
- };
173
- const getModuleVersion = async (name, cwd)=>{
174
- const pkg = await getModule(name, cwd);
175
- return pkg?.version || null;
176
141
  };
177
- const installDependencies = async (install, { cwd, logger })=>{
142
+ const installAdminPeerDeps = async (missing, { cwd, logger })=>{
178
143
  const packageManager = managers.getPackageManager();
179
144
  if (!packageManager) {
180
145
  logger.error('Could not find a supported package manager, please install the dependencies manually.');
@@ -185,7 +150,7 @@ const installDependencies = async (install, { cwd, logger })=>{
185
150
  cwd,
186
151
  stdio: 'inherit'
187
152
  };
188
- const packages = install.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`);
153
+ const packages = missing.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`);
189
154
  let result;
190
155
  if (packageManager === 'npm') {
191
156
  const npmArgs = [
@@ -216,7 +181,39 @@ const installDependencies = async (install, { cwd, logger })=>{
216
181
  throw new Error('Package installation failed');
217
182
  }
218
183
  };
184
+ const reexecCurrentCommand = async (cwd)=>{
185
+ const [file, ...args] = process.argv;
186
+ /**
187
+ * Re-run the same command after installation e.g. strapi build because the yarn.lock might
188
+ * not be the same and could break installations. It's not the best solution, but it works.
189
+ */ await execa(file, args, {
190
+ cwd,
191
+ stdio: 'inherit'
192
+ });
193
+ };
194
+ const getModule = async (name, cwd)=>{
195
+ const modulePackagePath = resolveFrom.silent(cwd, path.join(name, 'package.json'));
196
+ if (!modulePackagePath) {
197
+ return null;
198
+ }
199
+ const file = await fs.readFile(modulePackagePath, 'utf8').then((res)=>JSON.parse(res));
200
+ return file;
201
+ };
202
+ const getModuleVersion = async (name, cwd)=>{
203
+ const pkg = await getModule(name, cwd);
204
+ return pkg?.version || null;
205
+ };
219
206
 
220
- exports.checkRequiredDependencies = checkRequiredDependencies;
207
+ exports.ADMIN_PEER_DEPS = ADMIN_PEER_DEPS;
208
+ exports.MissingAdminPeerDepsError = MissingAdminPeerDepsError;
209
+ exports.findUndeclaredAdminPeerDeps = findUndeclaredAdminPeerDeps;
210
+ exports.getInstallCommandHint = getInstallCommandHint;
221
211
  exports.getModule = getModule;
212
+ exports.hashPackageJson = hashPackageJson;
213
+ exports.installAdminPeerDeps = installAdminPeerDeps;
214
+ exports.readCachedHash = readCachedHash;
215
+ exports.reexecCurrentCommand = reexecCurrentCommand;
216
+ exports.reportMissingAdminPeerDeps = reportMissingAdminPeerDeps;
217
+ exports.validateDeclaredAdminPeerDeps = validateDeclaredAdminPeerDeps;
218
+ exports.writeCachedHash = writeCachedHash;
222
219
  //# sourceMappingURL=dependencies.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dependencies.js","sources":["../../../../src/node/core/dependencies.ts"],"sourcesContent":["import os from 'node:os';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\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\nconst CACHE_PATH = path.join('node_modules', '.strapi', 'deps-check.hash');\n\nconst hashPackageJson = async (cwd: string): Promise<string | null> => {\n try {\n const content = await fs.readFile(path.join(cwd, 'package.json'), 'utf8');\n return crypto.createHash('sha1').update(content).digest('hex');\n } catch {\n return null;\n }\n};\n\nconst readCachedHash = (cwd: string): Promise<string | null> =>\n fs.readFile(path.join(cwd, CACHE_PATH), 'utf8').catch(() => null);\n\nconst writeCachedHash = async (cwd: string, hash: string): Promise<void> => {\n try {\n await fs.mkdir(path.dirname(path.join(cwd, CACHE_PATH)), { recursive: true });\n await fs.writeFile(path.join(cwd, CACHE_PATH), hash, 'utf8');\n } catch {\n // best-effort cache write — silently ignore\n }\n};\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 // Hash-cache: skip the full check when package.json hasn't changed since\n // the last successful pass. The cache lives under node_modules so it's\n // already gitignored and disposable (a `yarn install` wipe re-runs it).\n const currentHash = await hashPackageJson(cwd);\n if (currentHash) {\n const cachedHash = await readCachedHash(cwd);\n if (cachedHash === currentHash) {\n return { didInstall: false };\n }\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 =\n pkg.packageJson.dependencies[name] ?? pkg.packageJson.devDependencies?.[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 if (currentHash) {\n await writeCachedHash(cwd, currentHash);\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":["CACHE_PATH","path","join","hashPackageJson","cwd","content","fs","readFile","crypto","createHash","update","digest","readCachedHash","catch","writeCachedHash","hash","mkdir","dirname","recursive","writeFile","PEER_DEPS","react","checkRequiredDependencies","logger","process","env","USE_EXPERIMENTAL_DEPENDENCIES","warn","didInstall","currentHash","cachedHash","pkg","readPkgUp","Error","debug","os","EOL","packageJson","install","review","Object","entries","reduce","acc","name","version","dependencies","declaredVersion","devDependencies","push","wantedVersion","length","info","map","installDependencies","file","args","argv","execa","stdio","errors","dep","minDeclaredVersion","semver","minVersion","err","satisfies","installedVersion","getModuleVersion","NODE_ENV","getModule","modulePackagePath","resolveFrom","silent","then","res","JSON","parse","packageManager","getPackageManager","error","exit","execOptions","encoding","packages","result","npmArgs","yarnArgs","pnpmArgs","exitCode","failed"],"mappings":"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"}
1
+ {"version":3,"file":"dependencies.js","sources":["../../../../src/node/core/dependencies.ts"],"sourcesContent":["import os from 'node:os';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport semver, { SemVer } from 'semver';\nimport resolveFrom from 'resolve-from';\nimport execa, { CommonOptions, ExecaReturnValue } from 'execa';\nimport readPkgUp, { PackageJson } from 'read-pkg-up';\n\nimport type { Logger } from '../../cli/utils/logger';\nimport { getPackageManager } from './managers';\n\nconst CACHE_PATH = path.join('node_modules', '.strapi', 'deps-check.hash');\n\nconst hashPackageJson = async (cwd: string): Promise<string | null> => {\n try {\n const content = await fs.readFile(path.join(cwd, 'package.json'), 'utf8');\n return crypto.createHash('sha1').update(content).digest('hex');\n } catch {\n return null;\n }\n};\n\nconst readCachedHash = (cwd: string): Promise<string | null> =>\n fs.readFile(path.join(cwd, CACHE_PATH), 'utf8').catch(() => null);\n\nconst writeCachedHash = async (cwd: string, hash: string): Promise<void> => {\n try {\n await fs.mkdir(path.dirname(path.join(cwd, CACHE_PATH)), { recursive: true });\n await fs.writeFile(path.join(cwd, CACHE_PATH), hash, 'utf8');\n } catch {\n // best-effort cache write — silently ignore\n }\n};\n\n/**\n * From V5 this will be imported from the package.json of `@strapi/strapi`.\n */\nconst ADMIN_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} as const;\n\ninterface AdminPeerDep {\n name: string;\n wantedVersion: string;\n}\n\ninterface DeclaredAdminPeerDep extends AdminPeerDep {\n declaredVersion: string;\n}\n\nclass MissingAdminPeerDepsError extends Error {\n readonly missing: AdminPeerDep[];\n\n constructor(missing: AdminPeerDep[]) {\n super('Missing required dependencies. Please install them and re-run this command.');\n this.name = 'MissingAdminPeerDepsError';\n this.missing = missing;\n }\n}\n\nconst loadProjectPackageJson = async (cwd: string) => {\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 if (!pkg.packageJson.dependencies) {\n throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);\n }\n\n return pkg;\n};\n\n/**\n * Returns admin peer dependencies that are not declared in the project's package.json.\n */\nconst findUndeclaredAdminPeerDeps = async (cwd: string): Promise<AdminPeerDep[]> => {\n const pkg = await loadProjectPackageJson(cwd);\n\n return Object.entries(ADMIN_PEER_DEPS).reduce<AdminPeerDep[]>((missing, [name, version]) => {\n const declaredVersion =\n pkg.packageJson.dependencies?.[name] ?? pkg.packageJson.devDependencies?.[name];\n\n if (!declaredVersion) {\n missing.push({\n name,\n wantedVersion: version,\n });\n }\n\n return missing;\n }, []);\n};\n\nconst getDeclaredAdminPeerDeps = (packageJson: PackageJson): DeclaredAdminPeerDep[] => {\n return Object.entries(ADMIN_PEER_DEPS).reduce<DeclaredAdminPeerDep[]>(\n (declared, [name, version]) => {\n const declaredVersion =\n packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name];\n\n if (declaredVersion) {\n declared.push({\n name,\n wantedVersion: version,\n declaredVersion,\n });\n }\n\n return declared;\n },\n []\n );\n};\n\nconst getInstallCommandHint = (missing: AdminPeerDep[]) => {\n const packages = missing.map(({ name, wantedVersion }) => `${name}@${wantedVersion}`).join(' ');\n const packageManager = getPackageManager();\n\n if (packageManager === 'yarn') {\n return `yarn add ${packages}`;\n }\n\n if (packageManager === 'pnpm') {\n return `pnpm add --save-prod ${packages}`;\n }\n\n return `npm install --legacy-peer-deps --save ${packages}`;\n};\n\nconst reportMissingAdminPeerDeps = (logger: Logger, missing: AdminPeerDep[]) => {\n logger.error(\n 'The Strapi admin is missing required dependencies:',\n os.EOL,\n missing.map(({ name, wantedVersion }) => ` - ${name}@${wantedVersion}`).join(os.EOL)\n );\n logger.error(\n 'Please install them manually before re-running this command:',\n os.EOL,\n ` ${getInstallCommandHint(missing)}`\n );\n};\n\n/**\n * Validates declared admin peer dependencies (versions and node_modules presence).\n */\nconst validateDeclaredAdminPeerDeps = async (cwd: string, logger: Logger) => {\n const pkg = await loadProjectPackageJson(cwd);\n const declared = getDeclaredAdminPeerDeps(pkg.packageJson);\n\n if (!declared.length) {\n return;\n }\n\n logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);\n\n const errors: string[] = [];\n\n for (const dep of declared) {\n let minDeclaredVersion: SemVer | null = null;\n\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 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 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\nconst installAdminPeerDeps = async (\n missing: AdminPeerDep[],\n { cwd, logger }: { cwd: string; logger: 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 = missing.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\nconst reexecCurrentCommand = async (cwd: string) => {\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};\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\nexport {\n ADMIN_PEER_DEPS,\n findUndeclaredAdminPeerDeps,\n validateDeclaredAdminPeerDeps,\n installAdminPeerDeps,\n reexecCurrentCommand,\n reportMissingAdminPeerDeps,\n getInstallCommandHint,\n MissingAdminPeerDepsError,\n getModule,\n hashPackageJson,\n readCachedHash,\n writeCachedHash,\n};\nexport type { AdminPeerDep, PackageJson };\n"],"names":["CACHE_PATH","path","join","hashPackageJson","cwd","content","fs","readFile","crypto","createHash","update","digest","readCachedHash","catch","writeCachedHash","hash","mkdir","dirname","recursive","writeFile","ADMIN_PEER_DEPS","react","MissingAdminPeerDepsError","Error","missing","name","loadProjectPackageJson","pkg","readPkgUp","packageJson","dependencies","findUndeclaredAdminPeerDeps","Object","entries","reduce","version","declaredVersion","devDependencies","push","wantedVersion","getDeclaredAdminPeerDeps","declared","getInstallCommandHint","packages","map","packageManager","getPackageManager","reportMissingAdminPeerDeps","logger","error","os","EOL","validateDeclaredAdminPeerDeps","length","debug","errors","dep","minDeclaredVersion","semver","minVersion","err","satisfies","warn","installedVersion","getModuleVersion","process","env","NODE_ENV","installAdminPeerDeps","exit","execOptions","encoding","stdio","result","npmArgs","info","execa","yarnArgs","pnpmArgs","exitCode","failed","reexecCurrentCommand","file","args","argv","getModule","modulePackagePath","resolveFrom","silent","then","res","JSON","parse"],"mappings":"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"}
@@ -30,149 +30,114 @@ const writeCachedHash = async (cwd, hash)=>{
30
30
  };
31
31
  /**
32
32
  * From V5 this will be imported from the package.json of `@strapi/strapi`.
33
- */ const PEER_DEPS = {
33
+ */ const ADMIN_PEER_DEPS = {
34
34
  react: '^18.0.0',
35
35
  'react-dom': '^18.0.0',
36
36
  'react-router-dom': '^6.0.0',
37
37
  'styled-components': '^6.0.0'
38
38
  };
39
- /**
40
- * Checks the user's project that it has declared and installed the required dependencies
41
- * needed by the Strapi admin project. Whilst generally speaking most modules will be
42
- * declared by the actual packages there are some packages where you only really want one of
43
- * and thus they are declared as peer dependencies – react / styled-components / etc.
44
- *
45
- * If these deps are not installed or declared, then we prompt the user to correct this. In
46
- * V4 this is not a hard requirement, but in V5 it will be. Might as well get people started now.
47
- */ const checkRequiredDependencies = async ({ cwd, logger })=>{
48
- /**
49
- * This enables us to use experimental deps for libraries like
50
- * react or styled-components. This is useful for testing against.
51
- */ if (process.env.USE_EXPERIMENTAL_DEPENDENCIES === 'true') {
52
- logger.warn('You are using experimental dependencies that may not be compatible with Strapi.');
53
- return {
54
- didInstall: false
55
- };
56
- }
57
- // Hash-cache: skip the full check when package.json hasn't changed since
58
- // the last successful pass. The cache lives under node_modules so it's
59
- // already gitignored and disposable (a `yarn install` wipe re-runs it).
60
- const currentHash = await hashPackageJson(cwd);
61
- if (currentHash) {
62
- const cachedHash = await readCachedHash(cwd);
63
- if (cachedHash === currentHash) {
64
- return {
65
- didInstall: false
66
- };
67
- }
39
+ class MissingAdminPeerDepsError extends Error {
40
+ constructor(missing){
41
+ super('Missing required dependencies. Please install them and re-run this command.');
42
+ this.name = 'MissingAdminPeerDepsError';
43
+ this.missing = missing;
68
44
  }
45
+ }
46
+ const loadProjectPackageJson = async (cwd)=>{
69
47
  const pkg = await readPkgUp({
70
48
  cwd
71
49
  });
72
50
  if (!pkg) {
73
51
  throw new Error(`Could not find package.json at path: ${cwd}`);
74
52
  }
75
- logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);
76
- /**
77
- * Run through each of the peer deps and figure out if they need to be
78
- * installed or they need their version checked against.
79
- */ const { install, review } = Object.entries(PEER_DEPS).reduce((acc, [name, version])=>{
80
- if (!pkg.packageJson.dependencies) {
81
- throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);
82
- }
83
- const declaredVersion = pkg.packageJson.dependencies[name] ?? pkg.packageJson.devDependencies?.[name];
53
+ if (!pkg.packageJson.dependencies) {
54
+ throw new Error(`Could not find dependencies in package.json at path: ${cwd}`);
55
+ }
56
+ return pkg;
57
+ };
58
+ /**
59
+ * Returns admin peer dependencies that are not declared in the project's package.json.
60
+ */ const findUndeclaredAdminPeerDeps = async (cwd)=>{
61
+ const pkg = await loadProjectPackageJson(cwd);
62
+ return Object.entries(ADMIN_PEER_DEPS).reduce((missing, [name, version])=>{
63
+ const declaredVersion = pkg.packageJson.dependencies?.[name] ?? pkg.packageJson.devDependencies?.[name];
84
64
  if (!declaredVersion) {
85
- acc.install.push({
65
+ missing.push({
86
66
  name,
87
67
  wantedVersion: version
88
68
  });
89
- } else {
90
- acc.review.push({
69
+ }
70
+ return missing;
71
+ }, []);
72
+ };
73
+ const getDeclaredAdminPeerDeps = (packageJson)=>{
74
+ return Object.entries(ADMIN_PEER_DEPS).reduce((declared, [name, version])=>{
75
+ const declaredVersion = packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name];
76
+ if (declaredVersion) {
77
+ declared.push({
91
78
  name,
92
79
  wantedVersion: version,
93
80
  declaredVersion
94
81
  });
95
82
  }
96
- return acc;
97
- }, {
98
- install: [],
99
- review: []
100
- });
101
- if (install.length > 0) {
102
- logger.info('The Strapi admin needs to install the following dependencies:', os.EOL, install.map(({ name, wantedVersion })=>` - ${name}@${wantedVersion}`).join(os.EOL));
103
- await installDependencies(install, {
104
- cwd,
105
- logger
106
- });
107
- const [file, ...args] = process.argv;
108
- /**
109
- * Re-run the same command after installation e.g. strapi build because the yarn.lock might
110
- * not be the same and could break installations. It's not the best solution, but it works.
111
- */ await execa(file, args, {
112
- cwd,
113
- stdio: 'inherit'
114
- });
115
- return {
116
- didInstall: true
117
- };
83
+ return declared;
84
+ }, []);
85
+ };
86
+ const getInstallCommandHint = (missing)=>{
87
+ const packages = missing.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`).join(' ');
88
+ const packageManager = getPackageManager();
89
+ if (packageManager === 'yarn') {
90
+ return `yarn add ${packages}`;
91
+ }
92
+ if (packageManager === 'pnpm') {
93
+ return `pnpm add --save-prod ${packages}`;
118
94
  }
119
- if (review.length) {
120
- const errors = [];
121
- for (const dep of review){
122
- // The version specified in package.json could be incorrect, eg `foo`
123
- let minDeclaredVersion = null;
124
- try {
125
- minDeclaredVersion = semver.minVersion(dep.declaredVersion);
126
- } catch (err) {
127
- // Intentional fall-through (variable will be left as null, throwing below)
128
- }
129
- if (!minDeclaredVersion) {
130
- errors.push(`The declared dependency, ${dep.name} has an invalid version in package.json: ${dep.declaredVersion}`);
131
- } else if (!semver.satisfies(minDeclaredVersion, dep.wantedVersion)) {
132
- /**
133
- * The delcared version should be semver compatible with our required version
134
- * of the dependency. If it's not, we should advise the user to change it.
135
- */ logger.warn([
136
- `Declared version of ${dep.name} (${minDeclaredVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
137
- 'You may experience issues, we recommend you change this.'
138
- ].join(os.EOL));
139
- }
140
- const installedVersion = await getModuleVersion(dep.name, cwd);
141
- if (!installedVersion) {
142
- /**
143
- * TODO: when we know the packageManager we can advise the actual install command.
144
- */ errors.push(`The declared dependency, ${dep.name} is not installed. You should install before re-running this command`);
145
- } else if (!semver.satisfies(installedVersion, dep.wantedVersion)) {
146
- logger.warn([
147
- `Declared version of ${dep.name} (${installedVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
148
- 'You may experience issues, we recommend you change this.'
149
- ].join(os.EOL));
150
- }
95
+ return `npm install --legacy-peer-deps --save ${packages}`;
96
+ };
97
+ const reportMissingAdminPeerDeps = (logger, missing)=>{
98
+ logger.error('The Strapi admin is missing required dependencies:', os.EOL, missing.map(({ name, wantedVersion })=>` - ${name}@${wantedVersion}`).join(os.EOL));
99
+ logger.error('Please install them manually before re-running this command:', os.EOL, ` ${getInstallCommandHint(missing)}`);
100
+ };
101
+ /**
102
+ * Validates declared admin peer dependencies (versions and node_modules presence).
103
+ */ const validateDeclaredAdminPeerDeps = async (cwd, logger)=>{
104
+ const pkg = await loadProjectPackageJson(cwd);
105
+ const declared = getDeclaredAdminPeerDeps(pkg.packageJson);
106
+ if (!declared.length) {
107
+ return;
108
+ }
109
+ logger.debug('Loaded package.json:', os.EOL, pkg.packageJson);
110
+ const errors = [];
111
+ for (const dep of declared){
112
+ let minDeclaredVersion = null;
113
+ try {
114
+ minDeclaredVersion = semver.minVersion(dep.declaredVersion);
115
+ } catch (err) {
116
+ // Intentional fall-through (variable will be left as null, throwing below)
151
117
  }
152
- if (errors.length > 0 && process.env.NODE_ENV === 'development') {
153
- throw new Error(`${os.EOL}- ${errors.join(`${os.EOL}- `)}`);
118
+ if (!minDeclaredVersion) {
119
+ errors.push(`The declared dependency, ${dep.name} has an invalid version in package.json: ${dep.declaredVersion}`);
120
+ } else if (!semver.satisfies(minDeclaredVersion, dep.wantedVersion)) {
121
+ logger.warn([
122
+ `Declared version of ${dep.name} (${minDeclaredVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
123
+ 'You may experience issues, we recommend you change this.'
124
+ ].join(os.EOL));
125
+ }
126
+ const installedVersion = await getModuleVersion(dep.name, cwd);
127
+ if (!installedVersion) {
128
+ errors.push(`The declared dependency, ${dep.name} is not installed. You should install before re-running this command`);
129
+ } else if (!semver.satisfies(installedVersion, dep.wantedVersion)) {
130
+ logger.warn([
131
+ `Declared version of ${dep.name} (${installedVersion}) is not compatible with the version required by Strapi (${dep.wantedVersion}).`,
132
+ 'You may experience issues, we recommend you change this.'
133
+ ].join(os.EOL));
154
134
  }
155
135
  }
156
- if (currentHash) {
157
- await writeCachedHash(cwd, currentHash);
158
- }
159
- return {
160
- didInstall: false
161
- };
162
- };
163
- const getModule = async (name, cwd)=>{
164
- const modulePackagePath = resolveFrom.silent(cwd, path.join(name, 'package.json'));
165
- if (!modulePackagePath) {
166
- return null;
136
+ if (errors.length > 0 && process.env.NODE_ENV === 'development') {
137
+ throw new Error(`${os.EOL}- ${errors.join(`${os.EOL}- `)}`);
167
138
  }
168
- const file = await fs.readFile(modulePackagePath, 'utf8').then((res)=>JSON.parse(res));
169
- return file;
170
- };
171
- const getModuleVersion = async (name, cwd)=>{
172
- const pkg = await getModule(name, cwd);
173
- return pkg?.version || null;
174
139
  };
175
- const installDependencies = async (install, { cwd, logger })=>{
140
+ const installAdminPeerDeps = async (missing, { cwd, logger })=>{
176
141
  const packageManager = getPackageManager();
177
142
  if (!packageManager) {
178
143
  logger.error('Could not find a supported package manager, please install the dependencies manually.');
@@ -183,7 +148,7 @@ const installDependencies = async (install, { cwd, logger })=>{
183
148
  cwd,
184
149
  stdio: 'inherit'
185
150
  };
186
- const packages = install.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`);
151
+ const packages = missing.map(({ name, wantedVersion })=>`${name}@${wantedVersion}`);
187
152
  let result;
188
153
  if (packageManager === 'npm') {
189
154
  const npmArgs = [
@@ -214,6 +179,28 @@ const installDependencies = async (install, { cwd, logger })=>{
214
179
  throw new Error('Package installation failed');
215
180
  }
216
181
  };
182
+ const reexecCurrentCommand = async (cwd)=>{
183
+ const [file, ...args] = process.argv;
184
+ /**
185
+ * Re-run the same command after installation e.g. strapi build because the yarn.lock might
186
+ * not be the same and could break installations. It's not the best solution, but it works.
187
+ */ await execa(file, args, {
188
+ cwd,
189
+ stdio: 'inherit'
190
+ });
191
+ };
192
+ const getModule = async (name, cwd)=>{
193
+ const modulePackagePath = resolveFrom.silent(cwd, path.join(name, 'package.json'));
194
+ if (!modulePackagePath) {
195
+ return null;
196
+ }
197
+ const file = await fs.readFile(modulePackagePath, 'utf8').then((res)=>JSON.parse(res));
198
+ return file;
199
+ };
200
+ const getModuleVersion = async (name, cwd)=>{
201
+ const pkg = await getModule(name, cwd);
202
+ return pkg?.version || null;
203
+ };
217
204
 
218
- export { checkRequiredDependencies, getModule };
205
+ export { ADMIN_PEER_DEPS, MissingAdminPeerDepsError, findUndeclaredAdminPeerDeps, getInstallCommandHint, getModule, hashPackageJson, installAdminPeerDeps, readCachedHash, reexecCurrentCommand, reportMissingAdminPeerDeps, validateDeclaredAdminPeerDeps, writeCachedHash };
219
206
  //# sourceMappingURL=dependencies.mjs.map