From 9f05f9a74c0e59287ed19f063ccd64d1c69456a3 Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Thu, 11 Jun 2020 08:58:14 -0700 Subject: [PATCH] feat(endo): Add search A Node.js application is a module and its transitive dependencies. To provide as close an approximation of Node.js, running an Endo application is also the importing of an entry module. To construct the compartment graph for the module, the search function starts with a path to the module and searches for the first parent directory that contains a "package.json". Node.js does not require there to be a "package.json". Neither do web applications using ESM or Deno applications. This is a constraint that we might relax in a future version by creating a special compartment for entry modules. --- packages/endo/src/search.js | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/endo/src/search.js diff --git a/packages/endo/src/search.js b/packages/endo/src/search.js new file mode 100644 index 0000000000..a32f33669a --- /dev/null +++ b/packages/endo/src/search.js @@ -0,0 +1,38 @@ +import { relativize } from "./node-module-specifier.js"; +import { relative } from "./url.js"; + +// q, as in quote, for enquoting strings in error messages. +const q = JSON.stringify; + +const decoder = new TextDecoder(); + +// Searches for the first ancestor directory of a module file that contains a +// package.json. +// Probes by attempting to read the file, not stat. +// To avoid duplicate work later, returns the text of the package.json for +// inevitable later use. +export const search = async (read, modulePath) => { + let directory = new URL("./", modulePath).toString(); + for (;;) { + const packageDescriptorPath = new URL("package.json", directory).toString(); + // eslint-disable-next-line no-await-in-loop + const packageDescriptorBytes = await read(packageDescriptorPath).catch( + () => undefined + ); + if (packageDescriptorBytes !== undefined) { + const packageDescriptorText = decoder.decode(packageDescriptorBytes); + return { + packagePath: directory, + packageDescriptorText, + moduleSpecifier: relativize(relative(directory, modulePath)) + }; + } + const parentDirectory = new URL("../", directory).toString(); + if (parentDirectory === directory) { + throw new Error( + `Cannot find package.json along path to module ${q(modulePath)}` + ); + } + directory = parentDirectory; + } +};