|
| 1 | +// @ts-check |
| 2 | + |
1 | 3 | import fs from 'fs';
|
2 | 4 | import path from 'path';
|
3 | 5 | import { fileURLToPath } from 'url';
|
4 | 6 |
|
5 | 7 | /**
|
6 |
| - * @param {Object} workspace The package currently being processed |
7 |
| - * @param {string} workspace.cwd Path of the current package |
8 |
| - * @param {Object} workspace.manifest The content of `package.json` |
9 |
| - * @returns {{ |
10 |
| - * dependencies?: Record<string, string>; |
11 |
| - * peerDependencies?: Record<string, string>; |
12 |
| - * peerDependenciesMeta?: Record<string, { optional?: boolean }>; |
13 |
| - * }} |
| 8 | + * @typedef {() => boolean} ConditionalCheck |
14 | 9 | */
|
15 | 10 |
|
16 | 11 | /**
|
17 |
| - * These are the dependencies we want to ensure exist in each folder. They will not override |
18 |
| - * the dependencies in the package.json if already present. |
| 12 | + * Get the package.json manifest for a given folder. |
| 13 | + * @param {string} folder |
| 14 | + * @returns {import('@rnx-kit/tools-packages').PackageInfo['manifest']} |
19 | 15 | */
|
20 |
| -const scriptDependencies = getScriptFolderDependencies(['typescript', 'eslint', 'just-scripts']); |
| 16 | +function getPackageManifest(folder) { |
| 17 | + const manifestPath = path.join(folder, 'package.json'); |
| 18 | + return JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); |
| 19 | +} |
| 20 | + |
| 21 | +// Get the versions once, so we don't query again on each package |
| 22 | +const scriptFolder = path.dirname(fileURLToPath(import.meta.url)); |
| 23 | +const scriptManifest = getPackageManifest(scriptFolder); |
| 24 | +const rootManifest = getPackageManifest(path.dirname(scriptFolder)); |
| 25 | +// all merged versions from the root and script manifests, scripts having precedence |
| 26 | +const baseVersions = { |
| 27 | + ...rootManifest?.devDependencies, |
| 28 | + ...rootManifest?.dependencies, |
| 29 | + ...scriptManifest?.devDependencies, |
| 30 | + ...scriptManifest?.dependencies, |
| 31 | +}; |
21 | 32 |
|
22 | 33 | /**
|
23 |
| - * Get the dependencies for the script folder, both `devDependencies` and `dependencies` |
24 |
| - * @param {string[]} keys - The keys of the dependencies to include |
25 |
| - * @returns {Record<string, string>} A map of dependencies for the script folder |
| 34 | + * Conditionally add a dependency to the given dependencies object if it is not already present |
| 35 | + * @param {string[]} depsToAdd |
| 36 | + * @param {import('@rnx-kit/tools-packages').PackageInfo['manifest']} manifest |
| 37 | + * @param {ConditionalCheck | boolean | undefined} condition |
| 38 | + * @returns {Record<string, string>} |
26 | 39 | */
|
27 |
| -function getScriptFolderDependencies(keys) { |
28 |
| - const pkgJsonName = path.join(path.dirname(fileURLToPath(import.meta.url)), './package.json'); |
29 |
| - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonName, 'utf-8')); |
30 |
| - const mergedDeps = { ...pkgJson.devDependencies, ...pkgJson.dependencies }; |
31 |
| - return Object.fromEntries(Object.entries(mergedDeps).filter(([key]) => keys.includes(key))); |
| 40 | +function conditionallyAdd(depsToAdd, manifest, condition) { |
| 41 | + /** @type {Record<string, string>} */ |
| 42 | + const newDeps = {}; |
| 43 | + if (!condition || (typeof condition === 'function' ? condition() : condition)) { |
| 44 | + for (const dep of depsToAdd) { |
| 45 | + if (!manifest.dependencies?.[dep] && !manifest.devDependencies?.[dep]) { |
| 46 | + if (baseVersions[dep]) { |
| 47 | + // If the dependency is not already present, and the extra condition is met, add it |
| 48 | + newDeps[dep] = baseVersions[dep]; |
| 49 | + } else { |
| 50 | + // If the dependency is not found in the base versions, log a warning |
| 51 | + console.warn(`Dependency ${dep} not found in base versions. Skipping dynamic add.`); |
| 52 | + } |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + return newDeps; |
| 57 | +} |
| 58 | + |
| 59 | +function addPrettier(manifest) { |
| 60 | + return manifest && manifest.scripts && (manifest.scripts.prettier || manifest.scripts['prettier-fix']); |
32 | 61 | }
|
33 | 62 |
|
| 63 | +/** |
| 64 | + * Get the dynamic dependencies for the given package given the package root directory and its manifest. |
| 65 | + * @param {{cwd: string, manifest: import('@rnx-kit/tools-packages').PackageInfo['manifest']}} param0 |
| 66 | + * @returns { { dependencies: Record<string, string> } } |
| 67 | + */ |
34 | 68 | export default function ({ cwd, manifest }) {
|
35 | 69 | const dependenciesToAdd = {};
|
36 |
| - Object.keys(scriptDependencies).forEach((key) => { |
37 |
| - if ((manifest?.dependencies && manifest.dependencies[key]) || (manifest?.devDependencies && manifest.devDependencies[key])) { |
38 |
| - // If the dependency already exists in the package.json, skip it |
39 |
| - return; |
40 |
| - } |
41 |
| - dependenciesToAdd[key] = scriptDependencies[key]; |
42 |
| - }); |
| 70 | + const enableLinting = Boolean(manifest.scripts && manifest.scripts.lint); |
| 71 | + |
43 | 72 | return {
|
44 |
| - dependencies: dependenciesToAdd, |
| 73 | + dependencies: { |
| 74 | + ...conditionallyAdd(['typescript'], manifest, () => fs.existsSync(path.join(cwd, 'tsconfig.json'))), |
| 75 | + ...conditionallyAdd(['eslint'], manifest, enableLinting), |
| 76 | + ...conditionallyAdd(['prettier'], manifest, () => addPrettier(manifest)), |
| 77 | + }, |
45 | 78 | };
|
46 | 79 | }
|
0 commit comments