nbb icon indicating copy to clipboard operation
nbb copied to clipboard

Namespaces with `*` can't be found.

Open commiterate opened this issue 10 months ago • 5 comments

version

v1.3.196

platform

macOS Sequoia 15.3.2

problem

Namespace symbols with * don't seem to work.

$ bb repl-clj
Clojure 1.12.0

user=> (require '[test-nbb-ns.test-cljc :as test-cljc])
nil

user=> (test-cljc/hello)
"Hello from test-nbb-ns.test-cljc!"
nil

user=> (require '[test-nbb-ns.*test-cljc* :as *test-cljc*])
nil

user=> (*test-cljc*/hello)
"Hello from test-nbb-ns.*test-cljc*!"
nil
$ bb repl-cljs
Welcome to nbb v1.3.196!

user=> (require '[test-nbb-ns.test-cljc :as test-cljc])
nil

user=> (test-cljc/hello)
"Hello from test-nbb-ns.test-cljc!"
nil

user=> (require '[test-nbb-ns.*test-cljc* :as *test-cljc*])
"Error: Could not find namespace: test-nbb-ns.*test-cljc*"

user=> (require '[test-nbb-ns.test-cljs :as test-cljs])
nil

user=> (test-cljs/hello)
"Hello from test-nbb-ns.test-cljs!"
nil

user=> (require '[test-nbb-ns.*test-cljs* :as *test-cljs*])
"Error: Could not find namespace: test-nbb-ns.*test-cljs*"

There may be other characters which are allowed in symbols that don't work, but I haven't tested those.

https://clojure.org/reference/reader#_symbols

repro

https://github.com/commiterate/test-nbb-ns

This is using :local/root "." in nbb.edn to defer to deps.edn.

The generated .nbb has files for all the namespaces.

.nbb
└── .cache
    └── 234d643b78573b567a783af269377ad0cd729227
        ├── deps.edn
        ├── nbb-deps
        │   ├── META-INF
        │   │   └── MANIFEST.MF
        │   └── test_nbb_ns
        │       ├── *test_cljc*.cljc
        │       ├── *test_cljs*.cljs
        │       ├── test_cljc.cljc
        │       └── test_cljs.cljs
        └── nbb-deps.jar

expected behavior

Namespaces with * work like in Clojure (Java).

commiterate avatar Mar 15 '25 17:03 commiterate

It appears ClojureScript itself also suffers from this problem:

This is JVM Clojure:

$ clj
Clojure 1.11.1
user=> (require '[scittle.foo*])
:hello

This is a node REPL with normal CLJS:

$ clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "RELEASE"} org.clojure/tools.reader {:mvn/version "RELEASE"}}}' -M -m cljs.main -re node
ClojureScript 1.11.132
cljs.user=> (require '[scittle.foo*])
Unexpected error (ExceptionInfo) compiling at (<cljs repl>:1:1).
No such namespace: scittle.foo*, could not locate scittle/foo_STAR_.cljs, scittle/foo_STAR_.cljc, or JavaScript source providing "scittle.foo*" (Please check that namespaces with dashes use underscores in the ClojureScript file name) at line 1 <cljs repl>

borkdude avatar Mar 15 '25 18:03 borkdude

Hmm don't see an issue in the ClojureScript JIRA either from a cursory search nor is it mentioned in the ClojureScript differences from Clojure page.

commiterate avatar Mar 15 '25 18:03 commiterate

I think most people just avoid using * in filenames because it's very inconvenient in combination with bash, perhaps?

borkdude avatar Mar 15 '25 19:03 borkdude

Probably. I was using earmuffed namespace fragments for AWS infrastructure where we deploy identical stacks to multiple regions.

I'm modeling the deployment tree in Hiccup-like syntax:

my_service/infrastructure.cljs

(ns my-service.infrastructure
  (:require
    ["aws-cdk-lib" :as aws-cdk-lib]))

(def app
  (aws-cdk-lib/App.))

; Hiccup-like nodes of [type data & children].
;
; Stratified by service → stage → region.
(def service
  [:service
   {:name "my-service"}
   [:stage
    {:name "alpha"}
    [:region
     {:name "us-east-1"
      :account "000000000000"}]
    [:region
     {:name "us-west-2"
      :account "111111111111"}]]
   [:stage
    {:name "beta"}
    [:region
     {:name "us-east-1"
      :account "222222222222"}]
    [:region
     {:name "us-west-2"
      :account "333333333333"}]]])

; Calls a supplied function `f` with the node paths for a stratum.
;
; A node path is a vector of nodes from the parent to the child.
;
; Returns a map of node paths to the return value of `f`.
(defn map-stratum-paths
  [stratum-type f])

To prevent this infra file from being enormous, the resources are split across per-stratum ClojureScript files like my_service/infrastructure/*service*/*stage*/*region*.cljs. The earmuffs are used to indicate dynamism like how they're usually used for var names.

my_service/infrastructure/*service*/*stage*/*region*.cljs

(ns my-service.infrastructure.*service*.*stage*.*region*
  (:require
    ["aws-cdk-lib" :as aws-cdk-lib]
    ["aws-cdk-lib/aws-s3" :as s3]
    [clojure.string :as string]
    [my-service.infrastructure :as i]))

(def stacks
  (i/map-stratum-paths
    :region
    (fn
      [[[_ service-data & _] [_ stage-data & _] [_ region-data & _]]]
      (aws-cdk-lib/Stack.
        i/app
        (string/join "." [(service-data :name) (stage-data :name) (region-data :name)])
        (clj->js
          {:env {:account (region-data :account)
                 :region (region-data :name)}})))))

(def image-buckets
  (i/map-stratum-paths
    :region
    (fn
      [[[_ service-data & _] [_ stage-data & _] [_ region-data & _] :as node-path]]
      (s3/Bucket.
        (stacks node-path)
        "bucket"
        (clj->js
          {:bucketName (string/join "." [(service-data :name) (stage-data :name) (region-data :name) "image-bucket"])
           :publicAccessBlockConfiguration {:blockPublicAcls true
                                            :blockPublicPolicy true
                                            :ignorePublicAcls true
                                            :restrictPublicBuckets true}})))))

commiterate avatar Mar 15 '25 19:03 commiterate

Logged with CLJS as https://clojure.atlassian.net/browse/CLJS-3430

borkdude avatar Mar 17 '25 14:03 borkdude