|  | 
| 2781 | 2781 |            (if (and (.exists cljcf) (.isFile cljcf)) | 
| 2782 | 2782 |              cljcf)))))) | 
| 2783 | 2783 | 
 | 
|  | 2784 | +(defn external-dep? | 
|  | 2785 | +  "Returns true if the library is an :external? foreign dep. This means no source is provided | 
|  | 2786 | +  for the library, i.e. it will be provided by some script tag on the page, or loaded by some | 
|  | 2787 | +  other means into the JS execution environment." | 
|  | 2788 | +  #?(:cljs {:tag boolean}) | 
|  | 2789 | +  [dep] | 
|  | 2790 | +  (let [js-index (:js-dependency-index @env/*compiler*)] | 
|  | 2791 | +    (if-some [[_ {:keys [foreign external?]}] (find js-index (name (-> dep lib&sublib first)))] | 
|  | 2792 | +      (and foreign external?) | 
|  | 2793 | +      false))) | 
|  | 2794 | + | 
| 2784 | 2795 | (defn foreign-dep? | 
| 2785 | 2796 |   #?(:cljs {:tag boolean}) | 
| 2786 | 2797 |   [dep] | 
|  | 
| 2828 | 2839 |                           (error env | 
| 2829 | 2840 |                             (error-message :undeclared-ns {:ns-sym dep :js-provide (name dep)})))))))))))) | 
| 2830 | 2841 | 
 | 
|  | 2842 | +(defn global-ns? [x] | 
|  | 2843 | +  (or (= 'js x) | 
|  | 2844 | +      (= "js" (namespace x)))) | 
|  | 2845 | + | 
| 2831 | 2846 | (defn missing-use? [lib sym cenv] | 
| 2832 |  | -  (let [js-lib (get-in cenv [:js-dependency-index (name lib)])] | 
| 2833 |  | -    (and (= (get-in cenv [::namespaces lib :defs sym] ::not-found) ::not-found) | 
| 2834 |  | -         (not (= (get js-lib :group) :goog)) | 
| 2835 |  | -         (not (get js-lib :closure-lib)) | 
| 2836 |  | -         (not (node-module-dep? lib)) | 
| 2837 |  | -         (not (dep-has-global-exports? lib))))) | 
|  | 2847 | +  ;; ignore globals referred via :refer-global | 
|  | 2848 | +  (when-not (global-ns? lib) | 
|  | 2849 | +    (let [js-lib (get-in cenv [:js-dependency-index (name lib)])] | 
|  | 2850 | +      (and (= (get-in cenv [::namespaces lib :defs sym] ::not-found) ::not-found) | 
|  | 2851 | +        (not (= (get js-lib :group) :goog)) | 
|  | 2852 | +        (not (get js-lib :closure-lib)) | 
|  | 2853 | +        (not (node-module-dep? lib)) | 
|  | 2854 | +        (not (dep-has-global-exports? lib)))))) | 
| 2838 | 2855 | 
 | 
| 2839 | 2856 | (defn missing-rename? [sym cenv] | 
| 2840 | 2857 |   (let [lib (symbol (namespace sym)) | 
|  | 
| 3047 | 3064 |               ret | 
| 3048 | 3065 |               (recur fs ret true))))) | 
| 3049 | 3066 | 
 | 
|  | 3067 | +(defn parse-global-refer-spec | 
|  | 3068 | +  [env args] | 
|  | 3069 | +  (let [xs  (filter #(-> % first (= :refer-global)) args) | 
|  | 3070 | +        cnt (count xs)] | 
|  | 3071 | +    (cond | 
|  | 3072 | +      (> cnt 1) | 
|  | 3073 | +      (throw (error env "Only one :refer-global form is allowed per namespace definition")) | 
|  | 3074 | + | 
|  | 3075 | +      (== cnt 1) | 
|  | 3076 | +      (let [[_ & {:keys [only rename] :as parsed-spec}] (first xs) | 
|  | 3077 | +            only-set (set only) | 
|  | 3078 | +            err-str "Only (:refer-global :only [names]) and optionally `:rename {from to}` specs supported. | 
|  | 3079 | + :rename symbols must be present in :only"] | 
|  | 3080 | +        (when-not (or (empty? only) | 
|  | 3081 | +                      (and (vector? only) | 
|  | 3082 | +                           (every? symbol only))) | 
|  | 3083 | +          (throw (error env err-str))) | 
|  | 3084 | +        (when-not (or (empty? rename) | 
|  | 3085 | +                      (and (map? rename) | 
|  | 3086 | +                           (every? symbol (mapcat identity rename)) | 
|  | 3087 | +                           (every? only-set (keys rename)))) | 
|  | 3088 | +          (throw (error env (str err-str (pr-str parsed-spec))))) | 
|  | 3089 | +        (when-not (every? #{:only :rename} (keys parsed-spec)) | 
|  | 3090 | +          (throw (error env (str err-str (pr-str parsed-spec))))) | 
|  | 3091 | +        {:use    (zipmap only (repeat 'js)) | 
|  | 3092 | +         :rename (into {} | 
|  | 3093 | +                   (map (fn [[orig new-name]] | 
|  | 3094 | +                          [new-name (symbol "js" (str orig))])) | 
|  | 3095 | +                   rename)})))) | 
|  | 3096 | + | 
|  | 3097 | +(defn parse-global-require-spec | 
|  | 3098 | +  [env cenv deps aliases spec] | 
|  | 3099 | +  (if (or (symbol? spec) (string? spec)) | 
|  | 3100 | +    (recur env cenv deps aliases [spec]) | 
|  | 3101 | +    (do | 
|  | 3102 | +      (basic-validate-ns-spec env false spec) | 
|  | 3103 | +      (let [[lib & opts] spec | 
|  | 3104 | +            {alias :as referred :refer renamed :rename | 
|  | 3105 | +             :or {alias (if (string? lib) | 
|  | 3106 | +                          (symbol (munge lib)) | 
|  | 3107 | +                          lib)}} | 
|  | 3108 | +            (apply hash-map opts) | 
|  | 3109 | +            referred-without-renamed (seq (remove (set (keys renamed)) referred)) | 
|  | 3110 | +            [rk uk renk] [:require :use :rename]] | 
|  | 3111 | +        (when-not (or (symbol? alias) (nil? alias)) | 
|  | 3112 | +          (throw | 
|  | 3113 | +            (error env | 
|  | 3114 | +              (parse-ns-error-msg spec | 
|  | 3115 | +                ":as must be followed by a symbol in :require / :require-macros")))) | 
|  | 3116 | +        (when (some? alias) | 
|  | 3117 | +          (let [lib' ((:fns @aliases) alias)] | 
|  | 3118 | +            (when (and (some? lib') (not= lib lib')) | 
|  | 3119 | +              (throw (error env (parse-ns-error-msg spec ":as alias must be unique")))) | 
|  | 3120 | +            (when (= alias 'js) | 
|  | 3121 | +              (when-not (= lib (get-in @aliases [:fns 'js])) ; warn only once | 
|  | 3122 | +                (warning :js-used-as-alias env {:spec spec}))) | 
|  | 3123 | +            (swap! aliases update-in [:fns] conj [alias lib]))) | 
|  | 3124 | +        (when-not (or (and (sequential? referred) | 
|  | 3125 | +                           (every? symbol? referred)) | 
|  | 3126 | +                      (nil? referred)) | 
|  | 3127 | +          (throw | 
|  | 3128 | +            (error env | 
|  | 3129 | +              (parse-ns-error-msg spec | 
|  | 3130 | +                ":refer must be followed by a sequence of symbols in :require / :require-macros")))) | 
|  | 3131 | +        (swap! deps conj lib) | 
|  | 3132 | +        (let [ret (merge | 
|  | 3133 | +                    (when (some? alias) | 
|  | 3134 | +                      {rk (merge {alias lib} {lib lib})}) | 
|  | 3135 | +                    (when (some? referred-without-renamed) | 
|  | 3136 | +                      {uk (apply hash-map (interleave referred-without-renamed (repeat lib)))}) | 
|  | 3137 | +                    (when (some? renamed) | 
|  | 3138 | +                      {renk (reduce (fn [m [original renamed]] | 
|  | 3139 | +                                      (when-not (some #{original} referred) | 
|  | 3140 | +                                        (throw (error env | 
|  | 3141 | +                                                 (str "Renamed symbol " original " not referred")))) | 
|  | 3142 | +                                      (assoc m renamed (symbol (str lib) (str original)))) | 
|  | 3143 | +                              {} renamed)}))] | 
|  | 3144 | +          (swap! cenv assoc-in [:js-dependency-index (str lib)] | 
|  | 3145 | +            {:external?      true | 
|  | 3146 | +             :foreign        true | 
|  | 3147 | +             :provides       [(str lib)] | 
|  | 3148 | +             :global-exports {lib lib}}) | 
|  | 3149 | +          ret))))) | 
|  | 3150 | + | 
| 3050 | 3151 | (defn parse-require-spec [env macros? deps aliases spec] | 
| 3051 | 3152 |   (if (or (symbol? spec) (string? spec)) | 
| 3052 | 3153 |     (recur env macros? deps aliases [spec]) | 
|  | 
| 3300 | 3401 |                    (select-keys new deep-merge-keys)))) | 
| 3301 | 3402 |     new)) | 
| 3302 | 3403 | 
 | 
|  | 3404 | +(def ns-spec-cases | 
|  | 3405 | +  #{:use :use-macros :require :require-macros | 
|  | 3406 | +    :import :refer-global :require-global}) | 
|  | 3407 | + | 
| 3303 | 3408 | (defmethod parse 'ns | 
| 3304 | 3409 |   [_ env [_ name & args :as form] _ opts] | 
| 3305 | 3410 |   (when-not *allow-ns* | 
|  | 
| 3334 | 3439 |           core-renames (reduce (fn [m [original renamed]] | 
| 3335 | 3440 |                                  (assoc m renamed (symbol "cljs.core" (str original)))) | 
| 3336 | 3441 |                          {} core-renames) | 
|  | 3442 | +          {global-uses :use global-renames :rename} (parse-global-refer-spec env args) | 
| 3337 | 3443 |           deps         (atom []) | 
| 3338 | 3444 |           ;; as-aliases can only be used *once* because they are about the reader | 
| 3339 | 3445 |           aliases      (atom {:fns as-aliases :macros as-aliases}) | 
|  | 
| 3343 | 3449 |                                           (partial use->require env)) | 
| 3344 | 3450 |                         :use-macros     (comp (partial parse-require-spec env true deps aliases) | 
| 3345 | 3451 |                                           (partial use->require env)) | 
| 3346 |  | -                        :import         (partial parse-import-spec env deps)} | 
| 3347 |  | -          valid-forms  (atom #{:use :use-macros :require :require-macros :import}) | 
|  | 3452 | +                        :import         (partial parse-import-spec env deps) | 
|  | 3453 | +                        :require-global #(parse-global-require-spec env env/*compiler* deps aliases %)} | 
|  | 3454 | +          valid-forms  (atom #{:use :use-macros :require :require-macros :require-global :import}) | 
| 3348 | 3455 |           reload       (atom {:use nil :require nil :use-macros nil :require-macros nil}) | 
| 3349 | 3456 |           reloads      (atom {}) | 
| 3350 | 3457 |           {uses :use requires :require renames :rename | 
| 3351 | 3458 |            use-macros :use-macros require-macros :require-macros | 
| 3352 | 3459 |            rename-macros :rename-macros imports :import :as params} | 
| 3353 | 3460 |           (reduce | 
| 3354 | 3461 |             (fn [m [k & libs :as libspec]] | 
| 3355 |  | -              (when-not (#{:use :use-macros :require :require-macros :import} k) | 
| 3356 |  | -                (throw (error env (str "Only :refer-clojure, :require, :require-macros, :use, :use-macros, and :import libspecs supported. Got " libspec " instead.")))) | 
|  | 3462 | +              (when-not (#{:use :use-macros :require :require-macros :require-global :import} k) | 
|  | 3463 | +                (throw (error env (str "Only :refer-clojure, :require, :require-macros, :use, :use-macros, :require-global and :import libspecs supported. Got " libspec " instead.")))) | 
| 3357 | 3464 |               (when-not (@valid-forms k) | 
| 3358 | 3465 |                 (throw (error env (str "Only one " k " form is allowed per namespace definition")))) | 
| 3359 | 3466 |               (swap! valid-forms disj k) | 
|  | 
| 3370 | 3477 |               (apply merge-with merge m | 
| 3371 | 3478 |                 (map (spec-parsers k) | 
| 3372 | 3479 |                   (remove #{:reload :reload-all} libs)))) | 
| 3373 |  | -            {} (remove (fn [[r]] (= r :refer-clojure)) args)) | 
|  | 3480 | +            {} (remove (fn [[r]] (#{:refer-clojure :refer-global} r)) args)) | 
| 3374 | 3481 |           ;; patch `require-macros` and `use-macros` in Bootstrap for namespaces | 
| 3375 | 3482 |           ;; that require their own macros | 
| 3376 | 3483 |           #?@(:cljs [[require-macros use-macros] | 
|  | 
| 3392 | 3499 |              :use-macros     use-macros | 
| 3393 | 3500 |              :require-macros require-macros | 
| 3394 | 3501 |              :rename-macros  rename-macros | 
| 3395 |  | -             :uses           uses | 
|  | 3502 | +             :uses           (merge uses global-uses) | 
| 3396 | 3503 |              :requires       requires | 
| 3397 |  | -             :renames        (merge renames core-renames) | 
|  | 3504 | +             :renames        (merge renames core-renames global-renames) | 
| 3398 | 3505 |              :imports        imports}] | 
| 3399 | 3506 |         (swap! env/*compiler* update-in [::namespaces name] merge ns-info) | 
| 3400 | 3507 |         (merge {:op      :ns | 
|  | 
| 3434 | 3541 |         core-renames (reduce (fn [m [original renamed]] | 
| 3435 | 3542 |                                (assoc m renamed (symbol "cljs.core" (str original)))) | 
| 3436 | 3543 |                        {} core-renames) | 
|  | 3544 | +        {global-uses :use global-renames :rename} (parse-global-refer-spec env args) | 
| 3437 | 3545 |         deps         (atom []) | 
| 3438 | 3546 |         ;; as-aliases can only be used *once* because they are about the reader | 
| 3439 | 3547 |         aliases      (atom {:fns as-aliases :macros as-aliases}) | 
|  | 
| 3443 | 3551 |                                         (partial use->require env)) | 
| 3444 | 3552 |                       :use-macros     (comp (partial parse-require-spec env true deps aliases) | 
| 3445 | 3553 |                                         (partial use->require env)) | 
| 3446 |  | -                      :import         (partial parse-import-spec env deps)} | 
|  | 3554 | +                      :import         (partial parse-import-spec env deps) | 
|  | 3555 | +                      :require-global #(parse-global-require-spec env env/*compiler* deps aliases %)} | 
| 3447 | 3556 |         reload       (atom {:use nil :require nil :use-macros nil :require-macros nil}) | 
| 3448 | 3557 |         reloads      (atom {}) | 
| 3449 | 3558 |         {uses :use requires :require renames :rename | 
|  | 
| 3464 | 3573 |             (apply merge-with merge m | 
| 3465 | 3574 |               (map (spec-parsers k) | 
| 3466 | 3575 |                 (remove #{:reload :reload-all} libs)))) | 
| 3467 |  | -          {} (remove (fn [[r]] (= r :refer-clojure)) args))] | 
|  | 3576 | +          {} (remove (fn [[r]] (#{:refer-clojure :refer-global} r)) args))] | 
| 3468 | 3577 |     (set! *cljs-ns* name) | 
| 3469 | 3578 |     (let [require-info | 
| 3470 | 3579 |           {:as-aliases     as-aliases | 
|  | 
| 3473 | 3582 |            :use-macros     use-macros | 
| 3474 | 3583 |            :require-macros require-macros | 
| 3475 | 3584 |            :rename-macros  rename-macros | 
| 3476 |  | -           :uses           uses | 
|  | 3585 | +           :uses           (merge uses global-uses) | 
| 3477 | 3586 |            :requires       requires | 
| 3478 |  | -           :renames        (merge renames core-renames) | 
|  | 3587 | +           :renames        (merge renames core-renames global-renames) | 
| 3479 | 3588 |            :imports        imports}] | 
| 3480 | 3589 |       (swap! env/*compiler* update-in [::namespaces name] merge-ns-info require-info env) | 
| 3481 | 3590 |       (merge {:op      :ns* | 
|  | 
0 commit comments