Skip to content

Commit 8f400fc

Browse files
committed
tests and add recursive config processing
1 parent 7676e1d commit 8f400fc

File tree

2 files changed

+345
-21
lines changed

2 files changed

+345
-21
lines changed

packages/host/src/node/path-utils.test.ts

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,318 @@ describe("findNodeApiModulePathsByDependency", () => {
491491
});
492492
});
493493

494+
describe("findNodeApiModulePathsByConfiguration", () => {
495+
it("should find Node-API paths by dependency in root package.json configuration (excluding certain packages)", async (context) => {
496+
const packagesNames = ["lib-a", "lib-b", "lib-c", "lib-d", "lib-e"];
497+
const tempDir = setupTempDirectory(context, {
498+
"app/package.json": JSON.stringify({
499+
name: "app",
500+
dependencies: Object.fromEntries(
501+
packagesNames
502+
.slice(0, 2)
503+
.map((packageName) => [packageName, "^1.0.0"]),
504+
),
505+
reactNativeNodeApi: {
506+
scan: {
507+
dependencies: ["lib-e"],
508+
},
509+
},
510+
}),
511+
...Object.fromEntries(
512+
packagesNames.map((packageName) => [
513+
`app/node_modules/${packageName}`,
514+
{
515+
"package.json": JSON.stringify({
516+
name: packageName,
517+
main: "index.js",
518+
}),
519+
"index.js": "",
520+
"addon.apple.node/react-native-node-api-module": "",
521+
},
522+
]),
523+
),
524+
});
525+
526+
const result = await findNodeApiModulePathsByDependency({
527+
fromPath: path.join(tempDir, "app"),
528+
platform: "apple",
529+
includeSelf: false,
530+
excludePackages: ["lib-a"],
531+
});
532+
assert.deepEqual(result, {
533+
"lib-b": {
534+
path: path.join(tempDir, "app/node_modules/lib-b"),
535+
modulePaths: ["addon.apple.node"],
536+
},
537+
"lib-e": {
538+
path: path.join(tempDir, "app/node_modules/lib-e"),
539+
modulePaths: ["addon.apple.node"],
540+
},
541+
});
542+
});
543+
544+
it("should find Node-API paths by dependency in child modules configuration (excluding certain packages)", async (context) => {
545+
const packagesNames = ["lib-a", "lib-b", "lib-c", "lib-d", "lib-e"];
546+
const tempDir = setupTempDirectory(context, {
547+
"app/package.json": JSON.stringify({
548+
name: "app",
549+
dependencies: Object.fromEntries(
550+
packagesNames
551+
.slice(0, 3)
552+
.map((packageName) => [packageName, "^1.0.0"]),
553+
),
554+
}),
555+
...Object.fromEntries(
556+
packagesNames.slice(1).map((packageName, i) => [
557+
`app/node_modules/${packageName}`,
558+
{
559+
"package.json": JSON.stringify({
560+
name: packageName,
561+
main: "index.js",
562+
reactNativeNodeApi: {
563+
scan: {
564+
dependencies:
565+
packagesNames[i + 2] != null ? [packagesNames[i + 2]] : [],
566+
},
567+
},
568+
}),
569+
"index.js": "",
570+
"addon.apple.node/react-native-node-api-module": "",
571+
},
572+
]),
573+
),
574+
});
575+
576+
const result = await findNodeApiModulePathsByDependency({
577+
fromPath: path.join(tempDir, "app"),
578+
platform: "apple",
579+
includeSelf: false,
580+
excludePackages: ["lib-a"],
581+
});
582+
assert.deepEqual(result, {
583+
"lib-b": {
584+
path: path.join(tempDir, "app/node_modules/lib-b"),
585+
modulePaths: ["addon.apple.node"],
586+
},
587+
"lib-c": {
588+
path: path.join(tempDir, "app/node_modules/lib-c"),
589+
modulePaths: ["addon.apple.node"],
590+
},
591+
"lib-d": {
592+
path: path.join(tempDir, "app/node_modules/lib-d"),
593+
modulePaths: ["addon.apple.node"],
594+
},
595+
"lib-e": {
596+
path: path.join(tempDir, "app/node_modules/lib-e"),
597+
modulePaths: ["addon.apple.node"],
598+
},
599+
});
600+
});
601+
602+
it("shouldn't find Node-API paths that not set in any place", async (context) => {
603+
const packagesNames = ["lib-a", "lib-b", "lib-c", "lib-d", "lib-e"];
604+
const tempDir = setupTempDirectory(context, {
605+
"app/package.json": JSON.stringify({
606+
name: "app",
607+
dependencies: Object.fromEntries(
608+
packagesNames
609+
.slice(0, -1)
610+
.map((packageName) => [packageName, "^1.0.0"]),
611+
),
612+
}),
613+
...Object.fromEntries(
614+
packagesNames.slice(1).map((packageName) => [
615+
`app/node_modules/${packageName}`,
616+
{
617+
"package.json": JSON.stringify({
618+
name: packageName,
619+
main: "index.js",
620+
}),
621+
"index.js": "",
622+
"addon.apple.node/react-native-node-api-module": "",
623+
},
624+
]),
625+
),
626+
});
627+
628+
const result = await findNodeApiModulePathsByDependency({
629+
fromPath: path.join(tempDir, "app"),
630+
platform: "apple",
631+
includeSelf: false,
632+
excludePackages: ["lib-a"],
633+
});
634+
assert.deepEqual(result, {
635+
"lib-b": {
636+
path: path.join(tempDir, "app/node_modules/lib-b"),
637+
modulePaths: ["addon.apple.node"],
638+
},
639+
"lib-c": {
640+
path: path.join(tempDir, "app/node_modules/lib-c"),
641+
modulePaths: ["addon.apple.node"],
642+
},
643+
"lib-d": {
644+
path: path.join(tempDir, "app/node_modules/lib-d"),
645+
modulePaths: ["addon.apple.node"],
646+
},
647+
});
648+
});
649+
650+
it("shouldn't loop when searching Node-API paths", async (context) => {
651+
const packagesNames = ["lib-a", "lib-b", "lib-c", "lib-d", "lib-e"];
652+
const tempDir = setupTempDirectory(context, {
653+
"app/package.json": JSON.stringify({
654+
name: "app",
655+
dependencies: Object.fromEntries(
656+
packagesNames.map((packageName) => [packageName, "^1.0.0"]),
657+
),
658+
}),
659+
...Object.fromEntries(
660+
packagesNames.slice(1).map((packageName, i) => [
661+
`app/node_modules/${packageName}`,
662+
{
663+
"package.json": JSON.stringify({
664+
name: packageName,
665+
main: "index.js",
666+
reactNativeNodeApi: {
667+
scan: {
668+
dependencies:
669+
packagesNames[i + ((i % 2) * 2 - 1)] != null
670+
? [packagesNames[i + ((i % 2) * 2 - 1)]]
671+
: [],
672+
},
673+
},
674+
}),
675+
"index.js": "",
676+
"addon.apple.node/react-native-node-api-module": "",
677+
},
678+
]),
679+
),
680+
});
681+
682+
const result = await findNodeApiModulePathsByDependency({
683+
fromPath: path.join(tempDir, "app"),
684+
platform: "apple",
685+
includeSelf: false,
686+
excludePackages: ["lib-a"],
687+
});
688+
assert.deepEqual(result, {
689+
"lib-b": {
690+
path: path.join(tempDir, "app/node_modules/lib-b"),
691+
modulePaths: ["addon.apple.node"],
692+
},
693+
"lib-c": {
694+
path: path.join(tempDir, "app/node_modules/lib-c"),
695+
modulePaths: ["addon.apple.node"],
696+
},
697+
"lib-d": {
698+
path: path.join(tempDir, "app/node_modules/lib-d"),
699+
modulePaths: ["addon.apple.node"],
700+
},
701+
"lib-e": {
702+
path: path.join(tempDir, "app/node_modules/lib-e"),
703+
modulePaths: ["addon.apple.node"],
704+
},
705+
});
706+
});
707+
708+
it("should find Node-API paths by dependency in different layers config (excluding certain packages)", async (context) => {
709+
// lib-e - default module without node-api
710+
const packagesNames = [
711+
"lib-a",
712+
"lib-b",
713+
"lib-c",
714+
"lib-d",
715+
"lib-e",
716+
"lib-f",
717+
];
718+
const tempDir = setupTempDirectory(context, {
719+
"app/package.json": JSON.stringify({
720+
name: "app",
721+
dependencies: Object.fromEntries(
722+
packagesNames
723+
.slice(0, 2)
724+
.map((packageName) => [packageName, "^1.0.0"]),
725+
),
726+
}),
727+
"app/node_modules/lib-b": {
728+
"package.json": JSON.stringify({
729+
name: "lib-b",
730+
main: "index.js",
731+
dependencies: packagesNames.slice(2, 4),
732+
reactNativeNodeApi: {
733+
scan: {
734+
dependencies: packagesNames.slice(2, 4),
735+
},
736+
},
737+
}),
738+
"index.js": "",
739+
"addon.apple.node/react-native-node-api-module": "",
740+
},
741+
...Object.fromEntries(
742+
packagesNames.slice(2, 4).map((packageName, i) => [
743+
`app/node_modules/${packageName}`,
744+
{
745+
"package.json": JSON.stringify({
746+
name: packageName,
747+
main: "index.js",
748+
dependencies: [packagesNames[i + 4]],
749+
reactNativeNodeApi: {
750+
scan: {
751+
dependencies: [packagesNames[i + 4]],
752+
},
753+
},
754+
}),
755+
"index.js": "",
756+
"addon.apple.node/react-native-node-api-module": "",
757+
},
758+
]),
759+
),
760+
...Object.fromEntries(
761+
packagesNames.slice(4, 6).map((packageName) => [
762+
`app/node_modules/${packageName}`,
763+
{
764+
"package.json": JSON.stringify({
765+
name: packageName,
766+
main: "index.js",
767+
}),
768+
"index.js": "",
769+
"addon.apple.node/react-native-node-api-module": "",
770+
},
771+
]),
772+
),
773+
});
774+
775+
const result = await findNodeApiModulePathsByDependency({
776+
fromPath: path.join(tempDir, "app"),
777+
platform: "apple",
778+
includeSelf: false,
779+
excludePackages: ["lib-a"],
780+
});
781+
assert.deepEqual(result, {
782+
"lib-b": {
783+
path: path.join(tempDir, "app/node_modules/lib-b"),
784+
modulePaths: ["addon.apple.node"],
785+
},
786+
"lib-c": {
787+
path: path.join(tempDir, "app/node_modules/lib-c"),
788+
modulePaths: ["addon.apple.node"],
789+
},
790+
"lib-d": {
791+
path: path.join(tempDir, "app/node_modules/lib-d"),
792+
modulePaths: ["addon.apple.node"],
793+
},
794+
"lib-e": {
795+
path: path.join(tempDir, "app/node_modules/lib-e"),
796+
modulePaths: ["addon.apple.node"],
797+
},
798+
"lib-f": {
799+
path: path.join(tempDir, "app/node_modules/lib-f"),
800+
modulePaths: ["addon.apple.node"],
801+
},
802+
});
803+
});
804+
});
805+
494806
describe("determineModuleContext", () => {
495807
it("should read package.json only once across multiple module paths for the same package", (context) => {
496808
const tempDir = setupTempDirectory(context, {

packages/host/src/node/path-utils.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,9 @@ export function findPackageDependencyPaths(
345345
const packageRoot = packageDirectorySync({ cwd: fromPath });
346346
assert(packageRoot, `Could not find package root from ${fromPath}`);
347347

348-
const requireFromRoot = createRequire(path.join(packageRoot, "noop.js"));
348+
const requireFromRoot: NodeRequire = createRequire(
349+
path.join(packageRoot, "noop.js"),
350+
);
349351

350352
const packageJson = readPackageSync({
351353
cwd: packageRoot,
@@ -360,27 +362,37 @@ export function findPackageDependencyPaths(
360362
reactNativeNodeApi?.scan?.dependencies ?? [],
361363
);
362364

363-
return Object.fromEntries(
364-
initialDeps.flatMap((name) => {
365-
const root = resolvePackageRoot(requireFromRoot, name);
366-
if (!root) return [];
367-
368-
const nested =
369-
findPackageConfigurationByPath(root)?.reactNativeNodeApi?.scan
370-
?.dependencies ?? [];
371-
372-
const nestedEntries = nested
373-
.map((nestedName) => {
374-
const nestedRoot = resolvePackageRoot(requireFromRoot, nestedName);
375-
return nestedRoot
376-
? ([nestedName, nestedRoot] as [string, string])
377-
: null;
378-
})
379-
.filter((entry): entry is [string, string] => entry !== null);
365+
const result: Record<string, string> = {};
366+
const visited = new Set<string>();
367+
const queue: Array<string> = [...initialDeps];
380368

381-
return [[name, root] as [string, string], ...nestedEntries];
382-
}),
383-
);
369+
while (queue.length > 0) {
370+
const name = queue.shift()!;
371+
372+
if (visited.has(name)) {
373+
continue;
374+
}
375+
visited.add(name);
376+
377+
const root = resolvePackageRoot(requireFromRoot, name);
378+
if (!root) {
379+
continue;
380+
}
381+
382+
result[name] = root;
383+
384+
const config = findPackageConfigurationByPath(root);
385+
const nestedDependencies =
386+
config?.reactNativeNodeApi?.scan?.dependencies ?? [];
387+
388+
for (const nestedName of nestedDependencies) {
389+
if (!visited.has(nestedName)) {
390+
queue.push(nestedName);
391+
}
392+
}
393+
}
394+
395+
return result;
384396
}
385397

386398
export const MAGIC_FILENAME = "react-native-node-api-module";

0 commit comments

Comments
 (0)