diff --git a/src/main/clojure/cljs/foreign/node.clj b/src/main/clojure/cljs/foreign/node.clj index 0ae672295..e37794de2 100644 --- a/src/main/clojure/cljs/foreign/node.clj +++ b/src/main/clojure/cljs/foreign/node.clj @@ -50,31 +50,53 @@ (string/starts-with? path "./") (subs 2))) -(defn- ->export-pkg-json [path export] +(defn- ->export-pkg-json [package-path export] (io/file - (trim-package-json path) + (trim-package-json package-path) (trim-relative export) "package.json")) +(defn resolve-export + "Given an export value, find the entry point based on the + :package-json-resolution value, defaults to :nodejs. Returns nil + if we couldn't resolve it." + [export opts] + (if (string? export) + export + ;; we check for require to attempt to filter out + ;; strange cases, i.e. import but no require etc. + (when (and (map? export) (contains? export "require")) + (let [resolve (:package-json-resolution opts :nodejs) + lookup (if (sequential? resolve) + (or (some #{"import" "require"} resolve) "require") + ({:webpack "import" :nodejs "require"} resolve)) + entry (get export lookup)] + (if (map? entry) + (get entry "default") + entry))))) + (defn- export-subpaths - "Examine the export subpaths to compute subpackages" - [pkg-jsons export-subpath export path pkg-name] + "Examine the export subpaths to compute subpackages. Add them to pkg-json + parameter (this is a reduce-kv helper)." + [pkg-jsons export-subpath export package-path pkg-name opts] ;; NOTE: ignore "." exports for now (if (= "." export-subpath) - pkg-jsons + (if-let [resolved (resolve-export export opts)] + (assoc-in pkg-jsons [package-path "main"] resolved) + pkg-jsons) ;; technically the following logic is a bit brittle since `exports` is ;; supposed to be used to hide the package structure. ;; instead, here we assume the export subpath does match the library structure ;; on disk, if we find a package.json we add it to pkg-jsons map ;; and we synthesize "name" key based on subpath - (let [export-pkg-json (->export-pkg-json path export-subpath)] + (let [export-pkg-json-file (->export-pkg-json package-path export-subpath)] ;; note this will ignore export wildcards etc. (cond-> pkg-jsons - (.exists export-pkg-json) + (.exists export-pkg-json-file) (-> (assoc - (.getAbsolutePath export-pkg-json) + (.getAbsolutePath export-pkg-json-file) (merge - (json/read-str (slurp export-pkg-json)) + (json/read-str (slurp export-pkg-json-file)) ;; add the name field so that path->main-name works later (when (and (map? export) (contains? export "require")) @@ -92,14 +114,14 @@ detailed information." [pkg-jsons opts] (reduce-kv - (fn [pkg-jsons path {:strs [exports] :as pkg-json}] + (fn [pkg-jsons package-path {:strs [exports] :as pkg-json}] (if (string? exports) pkg-jsons ;; map case (reduce-kv (fn [pkg-jsons export-subpath export] - (export-subpaths pkg-jsons - export-subpath export path (get pkg-json "name"))) + (export-subpaths pkg-jsons export-subpath + export package-path (get pkg-json "name") opts)) pkg-jsons exports))) pkg-jsons pkg-jsons)) diff --git a/src/test/clojure/cljs/foreign/node_test.clj b/src/test/clojure/cljs/foreign/node_test.clj index 71c00ae40..926ccd03a 100644 --- a/src/test/clojure/cljs/foreign/node_test.clj +++ b/src/test/clojure/cljs/foreign/node_test.clj @@ -29,14 +29,20 @@ ;; ============================================================================= ;; Tests -(defn pkg-jsons [] - (-> (util/module-file-seq {}) - node/get-pkg-jsons)) +(defn pkg-jsons + ([] + (pkg-jsons {})) + ([opts] + (-> (util/module-file-seq opts) + (node/get-pkg-jsons opts)))) -(defn indexed-lib-specs [] - (as-> (-> (util/module-file-seq {}) - (node/node-file-seq->libs-spec* {})) - xs (zipmap (map :file xs) xs))) +(defn indexed-lib-specs + ([] + (indexed-lib-specs {})) + ([opts] + (as-> (-> (util/module-file-seq opts) + (node/node-file-seq->libs-spec* opts)) + xs (zipmap (map :file xs) xs)))) (defn relpath->data ([index path] @@ -60,27 +66,45 @@ (deftest test-path->main-name (install :yarn "react-select" "5.7.2") (testing "Verify that path->main works as expected" - (is (= "react-select" - (node/path->main-name + (let [node-opts {:package-json-resolution :nodejs} + webpack-opts {:package-json-resolution :webpack}] + (is (= "react-select" + (node/path->main-name (.getAbsolutePath (io/file "node_modules/react-select/dist/react-select.cjs.js")) - (relpath->data (pkg-jsons) + (relpath->data (pkg-jsons node-opts) "node_modules/react-select/package.json" :find) - {:package-json-resolution :nodejs}))) - (is (= "react-select/creatable" + node-opts))) + (is (= "react-select/creatable" (node/path->main-name (.getAbsolutePath (io/file "node_modules/react-select/creatable/dist/react-select-creatable.cjs.js")) - (relpath->data (pkg-jsons) + (relpath->data (pkg-jsons node-opts) "node_modules/react-select/creatable/package.json" :find) - {:package-json-resolution :nodejs}))) - (is (nil? (node/path->main-name - (.getAbsolutePath (io/file "node_modules/react-select/dist/react-select.cjs.js")) - (relpath->data (pkg-jsons) - "node_modules/react-select/package.json" :find) - {:package-json-resolution :webpack}))))) + node-opts))) + (is (nil? (node/path->main-name + (.getAbsolutePath (io/file "node_modules/react-select/dist/react-select.cjs.js")) + (relpath->data (pkg-jsons webpack-opts) + "node_modules/react-select/package.json" :find) + webpack-opts)))))) -(comment +(deftest test-exports-with-choices + (install :yarn "@mantine/core" "7.0.2") + (testing "Verify that complex exports are handled" + (let [node-opts {:package-json-resolution :nodejs} + webpack-opts {:package-json-resolution :webpack}] + (is (= "@mantine/core" + (node/path->main-name + (.getAbsolutePath (io/file "node_modules/@mantine/core/cjs/index.js")) + (relpath->data (pkg-jsons node-opts) + "node_modules/@mantine/core/package.json" :find) + node-opts))) + (is (= "@mantine/core" + (node/path->main-name + (.getAbsolutePath (io/file "node_modules/@mantine/core/esm/index.mjs")) + (relpath->data (pkg-jsons webpack-opts) + "node_modules/@mantine/core/package.json" :find) + webpack-opts)))))) +(comment (test/run-tests) (cleanup) - )