Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLJS-3404: Handle the case where NPM package.json exports defines *multiple* entry points #215

Merged
merged 1 commit into from
Sep 28, 2023
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
46 changes: 34 additions & 12 deletions src/main/clojure/cljs/foreign/node.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand All @@ -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))

Expand Down
66 changes: 45 additions & 21 deletions src/test/clojure/cljs/foreign/node_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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)

)
Loading