Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/cli-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"dependencies": {
"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",
Expand All @@ -21,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": [
Expand Down
24 changes: 24 additions & 0 deletions packages/cli-tools/src/__tests__/resolveNodeModuleDir.test.ts
Original file line number Diff line number Diff line change
@@ -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'),
);
});
});
102 changes: 102 additions & 0 deletions packages/cli-tools/src/findPackageDependencyDir.ts
Original file line number Diff line number Diff line change
@@ -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<T>(
obj: T,
keys: (keyof T)[],
names?: string[],
): Record<string, unknown> | undefined {
const finalNames = names ?? keys;
const results: Record<string, unknown> = {};

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;
}
18 changes: 12 additions & 6 deletions packages/cli-tools/src/resolveNodeModuleDir.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import path from 'path';
import {findPackageDependencyDir} from './findPackageDependencyDir';
import {CLIError} from './errors';

/**
* Finds a path inside `node_modules`
Expand All @@ -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;
}
}
36 changes: 35 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2623,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==
Expand Down Expand Up @@ -5644,6 +5644,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"
Expand Down Expand Up @@ -7856,6 +7864,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"
Expand Down Expand Up @@ -9213,6 +9228,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"
Expand All @@ -9234,6 +9256,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"
Expand Down Expand Up @@ -12528,3 +12557,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==