From 8cfb1c7a3b7510084bf2633761c1a17742d4c6d0 Mon Sep 17 00:00:00 2001 From: fortmarek Date: Mon, 25 Jul 2022 13:17:37 +0200 Subject: [PATCH 1/2] Fix resolving node modules directory with custom exports --- packages/cli-tools/package.json | 1 + .../__tests__/resolveNodeModuleDir.test.ts | 24 +++++++ .../cli-tools/src/resolveNodeModuleDir.ts | 18 ++++-- yarn.lock | 63 +++++++++++++++++++ 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 packages/cli-tools/src/__tests__/resolveNodeModuleDir.test.ts diff --git a/packages/cli-tools/package.json b/packages/cli-tools/package.json index 909cd8ed7..54271c86a 100644 --- a/packages/cli-tools/package.json +++ b/packages/cli-tools/package.json @@ -7,6 +7,7 @@ "access": "public" }, "dependencies": { + "@rnx-kit/tools-node": "^1.3.0", "appdirsjs": "^1.2.4", "chalk": "^4.1.2", "lodash": "^4.17.15", diff --git a/packages/cli-tools/src/__tests__/resolveNodeModuleDir.test.ts b/packages/cli-tools/src/__tests__/resolveNodeModuleDir.test.ts new file mode 100644 index 000000000..3024af155 --- /dev/null +++ b/packages/cli-tools/src/__tests__/resolveNodeModuleDir.test.ts @@ -0,0 +1,24 @@ +import {getTempDirectory, writeFiles} from '../../../../jest/helpers'; +import resolveNodeModuleDir from '../resolveNodeModuleDir'; +import path from 'path'; + +const DIR = getTempDirectory('resolve_node_module_dir_test'); + +describe('resolveNodeModuleDir', () => { + it('throws an error when node module directory does not exist', () => { + expect(() => + resolveNodeModuleDir(DIR, 'non-existing-package'), + ).toThrowError( + 'Node module directory for package non-existing-package was not found', + ); + }); + + it('returns resolved directory', () => { + writeFiles(DIR, { + 'node_modules/test-package/package.json': '{}', + }); + expect(resolveNodeModuleDir(DIR, 'test-package')).toEqual( + path.join(DIR, 'node_modules/test-package'), + ); + }); +}); diff --git a/packages/cli-tools/src/resolveNodeModuleDir.ts b/packages/cli-tools/src/resolveNodeModuleDir.ts index 7a03950cd..7dea7370c 100644 --- a/packages/cli-tools/src/resolveNodeModuleDir.ts +++ b/packages/cli-tools/src/resolveNodeModuleDir.ts @@ -1,4 +1,5 @@ -import path from 'path'; +import {findPackageDependencyDir} from '@rnx-kit/tools-node'; +import {CLIError} from './errors'; /** * Finds a path inside `node_modules` @@ -7,9 +8,14 @@ export default function resolveNodeModuleDir( root: string, packageName: string, ): string { - return path.dirname( - require.resolve(path.join(packageName, 'package.json'), { - paths: [root], - }), - ); + const packageDependencyDirectory = findPackageDependencyDir(packageName, { + startDir: root, + }); + if (packageDependencyDirectory === undefined) { + throw new CLIError( + `Node module directory for package ${packageName} was not found`, + ); + } else { + return packageDependencyDirectory; + } } diff --git a/yarn.lock b/yarn.lock index c09bd875c..0c01c8565 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2378,6 +2378,21 @@ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc" integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ== +"@rnx-kit/tools-language@^1.2.6": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@rnx-kit/tools-language/-/tools-language-1.3.1.tgz#7ab040becedd1426fbc58b0d6f8161df6d949add" + integrity sha512-PI5ouRAAT1UavccKw0c/Ufe/jubenU/6TWSphpGK4XdJ4/gV8gz9KOrALbSPrVCr0exrAaqf5p9QyBiPIFpriw== + +"@rnx-kit/tools-node@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@rnx-kit/tools-node/-/tools-node-1.3.0.tgz#8eb7a513ad9d2bba625cc9b1c5e9b033bb09045c" + integrity sha512-aUlKjcETkS3p6y2va4iFSpgUQ1QbzwxV54EgurGsJZ6FVv64LBc2FzgEVEVZ9IFwT/aVlc7JK4foC2LhT4rc5Q== + dependencies: + "@rnx-kit/tools-language" "^1.2.6" + find-up "^5.0.0" + pkg-dir "^5.0.0" + pkg-up "^3.1.0" + "@sinonjs/commons@^1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.1.tgz#da5fd19a5f71177a53778073978873964f49acf1" @@ -5644,6 +5659,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -7856,6 +7879,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -9213,6 +9243,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -9234,6 +9271,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map-series@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" @@ -9575,6 +9619,13 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" @@ -9582,6 +9633,13 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + plist@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe" @@ -12528,3 +12586,8 @@ yargs@^16.2.0: string-width "^4.2.0" y18n "^5.0.5" yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 3c6ec082b2567ef1db669b22df46872b0a92e6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 25 Jul 2022 17:58:39 +0200 Subject: [PATCH 2/2] vendor rnx-kit helpers to reduce node_modules size --- packages/cli-tools/package.json | 4 +- .../cli-tools/src/findPackageDependencyDir.ts | 102 ++++++++++++++++++ .../cli-tools/src/resolveNodeModuleDir.ts | 2 +- yarn.lock | 31 +----- 4 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 packages/cli-tools/src/findPackageDependencyDir.ts diff --git a/packages/cli-tools/package.json b/packages/cli-tools/package.json index 54271c86a..d45ed88d4 100644 --- a/packages/cli-tools/package.json +++ b/packages/cli-tools/package.json @@ -7,9 +7,9 @@ "access": "public" }, "dependencies": { - "@rnx-kit/tools-node": "^1.3.0", "appdirsjs": "^1.2.4", "chalk": "^4.1.2", + "find-up": "^5.0.0", "lodash": "^4.17.15", "mime": "^2.4.1", "node-fetch": "^2.6.0", @@ -22,7 +22,7 @@ "@react-native-community/cli-types": "^9.0.0-alpha.0", "@types/lodash": "^4.14.149", "@types/mime": "^2.0.1", - "@types/node": "^17.0.35", + "@types/node": "^12.0.0", "@types/node-fetch": "^2.5.5" }, "files": [ diff --git a/packages/cli-tools/src/findPackageDependencyDir.ts b/packages/cli-tools/src/findPackageDependencyDir.ts new file mode 100644 index 000000000..f8e02d0d0 --- /dev/null +++ b/packages/cli-tools/src/findPackageDependencyDir.ts @@ -0,0 +1,102 @@ +/** + * Source vendored from: + * https://github.com/microsoft/rnx-kit/blob/f37adca5161eba66fc27de25d48f72973fff9e8e/packages/tools-node/src/package.ts#L213-L234 + */ +import findUp from 'find-up'; +import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Pick the value for each `key` property from `obj` and return each one in a new object. + * If `names` are given, use them in the new object, instead of `keys`. + * + * If any `key` was not found or its value was `undefined`, nothing will be picked for that key. + * + * @param obj Object to pick from + * @param keys Keys to pick + * @param names Optional names to use in the output object + * @returns A new object containing a each `name` property and the picked value, or `undefined` if no keys were picked. + */ +export function pickValues( + obj: T, + keys: (keyof T)[], + names?: string[], +): Record | undefined { + const finalNames = names ?? keys; + const results: Record = {}; + + let pickedValue = false; + for (let index = 0; index < keys.length; ++index) { + const value = obj[keys[index]]; + if (typeof value !== 'undefined') { + results[finalNames[index].toString()] = value; + pickedValue = true; + } + } + + return pickedValue ? results : undefined; +} + +/** + * Components of a package reference. + */ +export type PackageRef = { + scope?: string; + name: string; +}; + +/** + * Options which control how package dependecies are located. + */ +export type FindPackageDependencyOptions = { + /** + * Optional starting directory for the search. Defaults to `process.cwd()`. + */ + startDir?: string; + + /** + * Optional flag controlling whether symlinks can be found. Defaults to `true`. + * When `false`, and the package dependency directory is a symlink, it will not + * be found. + */ + allowSymlinks?: boolean; + + /** + * Optional flag controlling whether to resolve symlinks. Defaults to `false`. + * Note that this flag has no effect if `allowSymlinks` is `false`. + */ + resolveSymlinks?: boolean; +}; + +/** + * Find the package dependency's directory, starting from the given directory + * and moving outward, through all parent directories. + * + * Package dependencies exist under 'node_modules/[`scope`]/[`name`]'. + * + * @param ref Package dependency reference + * @param options Options which control the search + * @returns Path to the package dependency's directory, or `undefined` if not found. + */ +export function findPackageDependencyDir( + ref: string | PackageRef, + options?: FindPackageDependencyOptions, +): string | undefined { + const pkgName = + typeof ref === 'string' ? ref : path.join(ref.scope ?? '', ref.name); + const packageDir = findUp.sync(path.join('node_modules', pkgName), { + ...pickValues( + options ?? {}, + ['startDir', 'allowSymlinks'], + ['cwd', 'allowSymlinks'], + ), + type: 'directory', + }); + if (!packageDir || !options?.resolveSymlinks) { + return packageDir; + } + + return fs.lstatSync(packageDir).isSymbolicLink() + ? path.resolve(path.dirname(packageDir), fs.readlinkSync(packageDir)) + : packageDir; +} diff --git a/packages/cli-tools/src/resolveNodeModuleDir.ts b/packages/cli-tools/src/resolveNodeModuleDir.ts index 7dea7370c..f7e5c06a3 100644 --- a/packages/cli-tools/src/resolveNodeModuleDir.ts +++ b/packages/cli-tools/src/resolveNodeModuleDir.ts @@ -1,4 +1,4 @@ -import {findPackageDependencyDir} from '@rnx-kit/tools-node'; +import {findPackageDependencyDir} from './findPackageDependencyDir'; import {CLIError} from './errors'; /** diff --git a/yarn.lock b/yarn.lock index 0c01c8565..d87c113aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2378,21 +2378,6 @@ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.1.0.tgz#e42b1bef12d2415411519fd528e64b593b1363dc" integrity sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ== -"@rnx-kit/tools-language@^1.2.6": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@rnx-kit/tools-language/-/tools-language-1.3.1.tgz#7ab040becedd1426fbc58b0d6f8161df6d949add" - integrity sha512-PI5ouRAAT1UavccKw0c/Ufe/jubenU/6TWSphpGK4XdJ4/gV8gz9KOrALbSPrVCr0exrAaqf5p9QyBiPIFpriw== - -"@rnx-kit/tools-node@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@rnx-kit/tools-node/-/tools-node-1.3.0.tgz#8eb7a513ad9d2bba625cc9b1c5e9b033bb09045c" - integrity sha512-aUlKjcETkS3p6y2va4iFSpgUQ1QbzwxV54EgurGsJZ6FVv64LBc2FzgEVEVZ9IFwT/aVlc7JK4foC2LhT4rc5Q== - dependencies: - "@rnx-kit/tools-language" "^1.2.6" - find-up "^5.0.0" - pkg-dir "^5.0.0" - pkg-up "^3.1.0" - "@sinonjs/commons@^1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.1.tgz#da5fd19a5f71177a53778073978873964f49acf1" @@ -2638,7 +2623,7 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@^12.0.0", "@types/node@^17.0.35": +"@types/node@*", "@types/node@^12.0.0": version "12.20.47" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== @@ -9619,13 +9604,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" @@ -9633,13 +9611,6 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - plist@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe"