<commit_before>(ns nha.boot-uglify.uglifyjs
  (:require [clojure.java.io :as io]
            [clojure.string  :as string]
            [cheshire.core   :refer [generate-string]]
            [nha.boot-uglify.nashorn :as jsexec :refer [create-engine eval-resource eval-str]])
  (:import
   [java.io StringWriter FileInputStream FileOutputStream File]
   [javax.script ScriptEngine ScriptEngineManager ScriptException ScriptEngineFactory]
   [org.apache.commons.lang3 StringEscapeUtils]
   [java.util.zip GZIPOutputStream]
   [java.util.logging Level]))


;;;;;;;;;;;;;;;;;;;;
;; Wraps UglifyJS
;; inside the available JS machine (Nashorn)


;; see
;; https://github.com/mishoo/UglifyJS2/issues/122
;; https://github.com/clojure/clojurescript/blob/c72e9c52156b3b348aa66857830c2ed1f0179e8c/src/main/clojure/cljs/repl/nashorn.clj#L29
;; https://github.com/adzerk-oss/boot-template/blob/master/src/adzerk/boot_template.clj
;; https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/api.html


(defn load-uglify
  "evaluate the Uglify JS files inside the provided engine"
  [engine]
  (eval-resource engine "Uglify2/uglifyjs.self.js")
  (eval-resource engine "Uglify2/compress.js")
  engine)

(defn create-uglify-engine
  []
  (-> (create-engine)
      (load-uglify)))

(defn escape-js
  "escape ecmascript code to get an escaped string
  useful for nested quotes"
  [s]
  (StringEscapeUtils/escapeEcmaScript s))

(defn uglify-str*
  "Minify a string"
  ([^String s] (uglify-str* (create-uglify-engine) s {}))
  ([engine ^String s] (uglify-str* (create-uglify-engine) s {}))
  ([engine ^String s opts]
   (let  [js-opts (generate-string (dissoc opts :mangle))
          mangle  (str (or (:mangle opts) false))
          code (str "var BOOT_UGLIFY_CODE =\"" (escape-js s) "\";"
                    "compress(BOOT_UGLIFY_CODE, " js-opts ", " mangle ");")]
     (eval-str engine code))))



;; To avoid creating a new Nashorn engine
;; and evaluate UglifyJS every time
;; TODO lazy creation?
(defonce js-engine (create-uglify-engine))

(defn uglify-str
  "Minify a String using Uglify-JS2"
  ([^String s] (uglify-str s {}))
  ([^String s opts] (uglify-str* js-engine s opts)))


(comment
  (escape-js "a = 'test'; // 'test' used here \n print(\"a is\",  a); ")
  (escape-js "a = \"test\"; // \"test\" used here")
  (escape-js "a = `test`; // 'test' used here")

  (uglify-str* "a = 'test'; // 'test' used here")
  (uglify-str* "var c = function myTest() {print('myTest'); return 123;}")<commit_msg>defonce only the first time<commit_after>(ns nha.boot-uglify.uglifyjs
  (:require [clojure.java.io :as io]
            [clojure.string  :as string]
            [cheshire.core   :refer [generate-string]]
            [nha.boot-uglify.nashorn :as jsexec :refer [create-engine eval-resource eval-str]])
  (:import
   [java.io StringWriter FileInputStream FileOutputStream File]
   [javax.script ScriptEngine ScriptEngineManager ScriptException ScriptEngineFactory]
   [org.apache.commons.lang3 StringEscapeUtils]
   [java.util.zip GZIPOutputStream]
   [java.util.logging Level]))


;;;;;;;;;;;;;;;;;;;;
;; Wraps UglifyJS
;; inside the available JS machine (Nashorn)


;; see
;; https://github.com/mishoo/UglifyJS2/issues/122
;; https://github.com/clojure/clojurescript/blob/c72e9c52156b3b348aa66857830c2ed1f0179e8c/src/main/clojure/cljs/repl/nashorn.clj#L29
;; https://github.com/adzerk-oss/boot-template/blob/master/src/adzerk/boot_template.clj
;; https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/api.html


(defn load-uglify
  "evaluate the Uglify JS files inside the provided engine"
  [engine]
  (eval-resource engine "Uglify2/uglifyjs.self.js")
  (eval-resource engine "Uglify2/compress.js")
  engine)

(defn create-uglify-engine
  []
  (-> (create-engine)
      (load-uglify)))

(defn escape-js
  "escape ecmascript code to get an escaped string
  useful for nested quotes"
  [s]
  (StringEscapeUtils/escapeEcmaScript s))

(defn uglify-str*
  "Minify a string"
  ([^String s] (uglify-str* (create-uglify-engine) s {}))
  ([engine ^String s] (uglify-str* (create-uglify-engine) s {}))
  ([engine ^String s opts]
   (let  [js-opts (generate-string (dissoc opts :mangle))
          mangle  (str (or (:mangle opts) false))
          code (str "var BOOT_UGLIFY_CODE =\"" (escape-js s) "\";"
                    "compress(BOOT_UGLIFY_CODE, " js-opts ", " mangle ");")]
     (eval-str engine code))))



;; To avoid creating a new Nashorn engine
;; and evaluate UglifyJS every time
;; but not use memory as soon as the ns is loaded
(defn maybe-init-uglify-engine []
  (defonce js-engine (create-uglify-engine)))


(defn uglify-str
  "Minify a String using Uglify-JS2"
  ([^String s] (uglify-str s {}))
  ([^String s opts]
   (maybe-init-uglify-engine)
   (uglify-str* js-engine s opts)))


(comment
  (escape-js "a = 'test'; // 'test' used here \n print(\"a is\",  a); ")
  (escape-js "a = \"test\"; // \"test\" used here")
  (escape-js "a = `test`; // 'test' used here")

  (uglify-str* "a = 'test'; // 'test' used here")
  (uglify-str* "var c = function myTest() {print('myTest'); return 123;}")
{'fraction_non_alphanumeric': 0.16211470932500976, 'fraction_numerical': 0.015996878657822865, 'mean_word_length': 3.6023339317773786, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5144574', 'n_tokens_mistral': 1974, 'n_tokens_neox': 1892, 'n_words': 426}