special form | since v0.0-927 | clojure.core/ns | Edit |
(ns name docstring? attr-map? references*)
Sets the namespace of the file.
ns
must be the first form in a .cljs
file and there can only be one ns
declaration per file. Namespaces must match the file name of their respective
.cljs
files, with the exception that dashes in namespaces become underscores
in filenames. Thus, (ns foo.bar-biz.baz)
should be the first form in file
foo/bar_biz/baz.cljs
.
references
can be zero or more forms used to import other namespaces, symbols,
and libraries into the current namespace.
(ns example.core
;; for excluding or renaming clojure symbols
(:refer-clojure
:exclude []
:rename {})
;; for importing goog classes and enums
(:import
lib.ns
(lib.ns Ctor*))
(:require
lib.ns
[lib.ns :refer []
:refer-macros []
:rename {}
:include-macros true|false
:as alias]
:reload
:reload-all)
(:use
lib.ns
[lib.ns :only []
:rename {}]
:reload
:reload-all)
(:require-macros
lib.ns
[lib.ns :refer []
:rename {}
:as alias]
:reload
:reload-all)
(:use-macros
lib.ns
[lib.ns :only []
:rename {}]
:reload
:reload-all))
You must currently use the ns form only with the following caveats * You must use the :only form of :use * :require supports :as, :refer, and :rename - all options can be skipped - in this case a symbol can be used as a libspec directly - that is, (:require lib.foo) and (:require [lib.foo]) are both supported and mean the same thing - :rename specifies a map from referred var names to different symbols (and can be used to prevent clashes) - prefix lists are not supported * The only options for :refer-clojure are :exclude and :rename * :import is available for importing Google Closure classes - ClojureScript types and records should be brought in with :use or :require :refer, not :import ed * Macros must be defined in a different compilation stage than the one from where they are consumed. One way to achieve this is to define them in one namespace and use them from another. They are referenced via the :require-macros / :use-macros options to ns - :require-macros and :use-macros support the same forms that :require and :use do Implicit macro loading: If a namespace is required or used, and that namespace itself requires or uses macros from its own namespace, then the macros will be implicitly required or used using the same specifications. Furthermore, in this case, macro vars may be included in a :refer or :only spec. This oftentimes leads to simplified library usage, such that the consuming namespace need not be concerned about explicitly distinguishing between whether certain vars are functions or macros. For example: (ns testme.core (:require [cljs.test :as test :refer [test-var deftest]])) will result in test/is resolving properly, along with the test-var function and the deftest macro being available unqualified. Inline macro specification: As a convenience, :require can be given either :include-macros true or :refer-macros [syms...]. Both desugar into forms which explicitly load the matching Clojure file containing macros. (This works independently of whether the namespace being required internally requires or uses its own macros.) For example: (ns testme.core (:require [foo.core :as foo :refer [foo-fn] :include-macros true] [woz.core :as woz :refer [woz-fn] :refer-macros [app jx]])) is sugar for (ns testme.core (:require [foo.core :as foo :refer [foo-fn]] [woz.core :as woz :refer [woz-fn]]) (:require-macros [foo.core :as foo] [woz.core :as woz :refer [app jx]])) Auto-aliasing clojure namespaces: If a non-existing clojure.* namespace is required or used and a matching cljs.* namespace exists, the cljs.* namespace will be loaded and an alias will be automatically established from the clojure.* namespace to the cljs.* namespace. For example: (ns testme.core (:require [clojure.test])) will be automatically converted to (ns testme.core (:require [cljs.test :as clojure.test]))
(defmethod parse 'ns
[_ env [_ name & args :as form] _ opts]
(when-not *allow-ns*
(throw (error env "Namespace declarations must appear at the top-level.")))
(when-not (symbol? name)
(throw (error env "Namespaces must be named by a symbol.")))
(let [name (cond-> name (:macros-ns opts) macro-ns-name)]
(let [segments (string/split (clojure.core/name name) #"\.")]
(when (= 1 (count segments))
(warning :single-segment-namespace env {:name name}))
(let [segment (some js-reserved segments)]
(when (some? segment)
(warning :munged-namespace env {:name name})))
(find-def-clash env name segments)
#?(:clj
(when (some (complement util/valid-js-id-start?) segments)
(throw
(AssertionError.
(str "Namespace " name " has a segment starting with an invaild "
"JavaScript identifier"))))))
(let [docstring (when (string? (first args)) (first args))
mdocstr (-> name meta :doc)
args (if (some? docstring) (next args) args)
metadata (when (map? (first args)) (first args))
args (desugar-ns-specs
#?(:clj (rewrite-cljs-aliases
(if metadata (next args) args))
:cljs (if (some? metadata) (next args) args)))
{:keys [as-aliases] args :libspecs} (nses/elide-aliases-from-ns-specs args)
name (vary-meta name merge metadata)
{excludes :excludes core-renames :renames} (parse-ns-excludes env args)
core-renames (reduce (fn [m [original renamed]]
(assoc m renamed (symbol "cljs.core" (str original))))
{} core-renames)
deps (atom [])
;; as-aliases can only be used *once* because they are about the reader
aliases (atom {:fns as-aliases :macros as-aliases})
spec-parsers {:require (partial parse-require-spec env false deps aliases)
:require-macros (partial parse-require-spec env true deps aliases)
:use (comp (partial parse-require-spec env false deps aliases)
(partial use->require env))
:use-macros (comp (partial parse-require-spec env true deps aliases)
(partial use->require env))
:import (partial parse-import-spec env deps)}
valid-forms (atom #{:use :use-macros :require :require-macros :import})
reload (atom {:use nil :require nil :use-macros nil :require-macros nil})
reloads (atom {})
{uses :use requires :require renames :rename
use-macros :use-macros require-macros :require-macros
rename-macros :rename-macros imports :import :as params}
(reduce
(fn [m [k & libs :as libspec]]
(when-not (#{:use :use-macros :require :require-macros :import} k)
(throw (error env (str "Only :refer-clojure, :require, :require-macros, :use, :use-macros, and :import libspecs supported. Got " libspec " instead."))))
(when-not (@valid-forms k)
(throw (error env (str "Only one " k " form is allowed per namespace definition"))))
(swap! valid-forms disj k)
;; check for spec type reloads
(when-not (= :import k)
(when (some? (some #{:reload} libs))
(swap! reload assoc k :reload))
(when (some? (some #{:reload-all} libs))
(swap! reload assoc k :reload-all)))
;; check for individual ns reloads from REPL interactions
(when-let [xs (seq (filter #(-> % meta :reload) libs))]
(swap! reloads assoc k
(zipmap (map first xs) (map #(-> % meta :reload) xs))))
(apply merge-with merge m
(map (spec-parsers k)
(remove #{:reload :reload-all} libs))))
{} (remove (fn [[r]] (= r :refer-clojure)) args))
;; patch `require-macros` and `use-macros` in Bootstrap for namespaces
;; that require their own macros
#?@(:cljs [[require-macros use-macros]
(map (fn [spec-map]
(if (:macros-ns opts)
(let [ns (symbol (subs (str name) 0 (- (count (str name)) 7)))]
(reduce (fn [m [k v]]
(cond-> m
(not (symbol-identical? v ns))
(assoc k v)))
{} spec-map))
spec-map)) [require-macros use-macros])])]
(set! *cljs-ns* name)
(let [ns-info
{:as-aliases as-aliases
:name name
:doc (or docstring mdocstr)
:excludes excludes
:use-macros use-macros
:require-macros require-macros
:rename-macros rename-macros
:uses uses
:requires requires
:renames (merge renames core-renames)
:imports imports}]
(swap! env/*compiler* update-in [::namespaces name] merge ns-info)
(merge {:op :ns
:env env
:form form
:deps (into [] (distinct @deps))
:reload @reload
:reloads @reloads}
(cond-> ns-info
(@reload :use)
(update-in [:uses]
(fn [m] (with-meta m {(@reload :use) true})))
(@reload :require)
(update-in [:requires]
(fn [m] (with-meta m {(@reload :require) true})))))))))
(defmethod emit* :ns
[{:keys [name requires uses require-macros reloads env deps]}]
(emitln "goog.provide('" (munge name) "');")
(when-not (= name 'cljs.core)
(emitln "goog.require('cljs.core');")
(when (-> @env/*compiler* :options :emit-constants)
(emitln "goog.require('" (munge ana/constants-ns-sym) "');")))
(load-libs requires nil (:require reloads) deps name)
(load-libs uses requires (:use reloads) deps name))