├── .gitignore ├── Clojurescript.iml ├── README.md ├── benchmark └── cljs │ └── benchmark_runner.cljs ├── bin ├── cljsc ├── cljsc.bat └── cljsc.clj ├── changes.md ├── devnotes ├── README.org ├── bcrepl.org ├── cljs.org ├── corelib.org ├── day1.org ├── day2.org ├── talk.org ├── testing └── todo.org ├── epl-v10.html ├── feature-macros-demo ├── Makefile ├── README.md ├── boot-shim.clj ├── boot.properties ├── build.boot ├── html │ └── index.html └── src │ ├── cemerick │ ├── url.clj │ └── url.cljs │ ├── demo.cljs.edn │ └── demo │ ├── core.clj │ ├── core.cljs │ ├── util.clj │ └── util.cljs ├── pom.template.xml ├── project.clj ├── samples ├── dom │ ├── .gitignore │ ├── src │ │ └── dom │ │ │ └── test.cljs │ └── test.html ├── hello-js │ ├── .gitignore │ ├── README.md │ ├── externed-lib.js │ ├── externs.js │ ├── hello-extern.html │ ├── hello-js-dev.html │ ├── hello-js.html │ ├── my-external-lib.js │ └── src │ │ └── hello-js │ │ ├── core.cljs │ │ └── extern-example.cljs ├── hello │ ├── .gitignore │ ├── README.md │ ├── hello-dev.html │ ├── hello.html │ └── src │ │ └── hello │ │ ├── core.cljs │ │ └── foo │ │ └── bar.cljs ├── nodehello.cljs ├── nodels.cljs ├── repl │ ├── .gitignore │ ├── README.md │ ├── index.html │ └── src │ │ └── repl │ │ └── test.cljs └── twitterbuzz │ ├── .gitignore │ ├── README.md │ ├── index-advanced.html │ ├── index.html │ ├── reset.css │ ├── src │ └── twitterbuzz │ │ ├── anneal.cljs │ │ ├── core.cljs │ │ ├── dom-helpers.cljs │ │ ├── layout.cljs │ │ ├── leaderboard.cljs │ │ ├── radial.cljs │ │ ├── showgraph.cljs │ │ └── timeline.cljs │ ├── style.css │ ├── test_data.txt │ └── tweet_maps.txt ├── script ├── benchmark ├── bootstrap ├── browser-repl ├── build ├── clean ├── closure-library-release │ ├── .gitignore │ ├── closure-library-release.sh │ ├── google-closure-library-third-party.pom.template │ └── google-closure-library.pom.template ├── compile ├── noderepljs ├── repl ├── repl.bat ├── repljs ├── repljs.bat ├── self-compile ├── test ├── test-compile └── test-simple ├── src ├── clj │ └── cljs │ │ ├── analyzer.clj │ │ ├── analyzer │ │ ├── api.clj │ │ └── utils.clj │ │ ├── build │ │ └── api.clj │ │ ├── closure.clj │ │ ├── compiler.clj │ │ ├── core.clj │ │ ├── env.clj │ │ ├── js_deps.clj │ │ ├── repl.clj │ │ ├── repl │ │ ├── browser.clj │ │ ├── node.clj │ │ ├── node_repl.js │ │ ├── reflect.clj │ │ ├── rhino.clj │ │ └── server.clj │ │ ├── source_map.clj │ │ ├── source_map │ │ ├── base64.clj │ │ └── base64_vlq.clj │ │ ├── tagged_literals.clj │ │ ├── test.clj │ │ └── util.clj └── cljs │ ├── cljs │ ├── bootstrap_node.js │ ├── core.cljs │ ├── externs.js │ ├── imul.js │ ├── nodejs.cljs │ ├── nodejs_externs.js │ ├── nodejscli.cljs │ ├── pprint.clj │ ├── pprint.cljs │ ├── reader.cljs │ ├── repl.cljs │ ├── source_map.cljs │ ├── source_map │ │ ├── base64.cljs │ │ └── base64_vlq.cljs │ └── test.cljs │ └── clojure │ ├── browser │ ├── dom.cljs │ ├── event.cljs │ ├── net.cljs │ └── repl.cljs │ ├── core │ └── reducers.cljs │ ├── data.cljs │ ├── reflect.cljs │ ├── set.cljs │ ├── string.cljs │ ├── walk.cljs │ └── zip.cljs └── test ├── clj └── cljs │ ├── analyzer_tests.clj │ ├── build_api_tests.clj │ ├── closure_tests.clj │ ├── compiler_tests.clj │ ├── preamble1.js │ ├── preamble2.js │ └── repl_tests.clj ├── cljs ├── baz.cljs ├── cljs │ ├── binding_test.cljs │ ├── binding_test_other_ns.cljs │ ├── core_test.cljs │ ├── import_test.cljs │ ├── keyword_other.cljs │ ├── keyword_test.cljs │ ├── letfn_test.cljs │ ├── macro_test.cljs │ ├── macro_test │ │ └── macros.clj │ ├── ns_test.cljs │ ├── ns_test │ │ ├── bar.cljs │ │ └── foo.cljs │ ├── reader_test.cljs │ ├── reducers_test.cljs │ └── top_level.cljs ├── clojure │ ├── data_test.cljs │ └── string_test.cljs ├── foo │ └── ns_shadow_test.cljs └── test_runner.cljs └── hello.cljs /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .idea 3 | /.DS_Store 4 | /classes 5 | /lib 6 | /target 7 | closure 8 | /core.js 9 | /coreadvanced.js 10 | /coresimple.js 11 | /out 12 | /pom.xml 13 | .repl* 14 | *.swp 15 | *.zip 16 | clojurescript_release_* 17 | closure-release-* 18 | .lein-repl-history 19 | .nrepl-port 20 | .nrepl-repl-history 21 | builds 22 | .cljs* 23 | node_modules 24 | 25 | feature-macros-demo/bin/ 26 | feature-macros-demo/target/ 27 | feature-macros-demo/.deps.time 28 | -------------------------------------------------------------------------------- /Clojurescript.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Feature Macros for Clojure / ClojureScript 2 | 3 | Please navigate to the [feature-macros-demo] directory for details. 4 | [feature-macros-demo]: https://github.com/feature-macros/clojurescript/tree/feature-macros/feature-macros-demo 5 | 6 | ## What is ClojureScript? ## 7 | 8 | ClojureScript is a new compiler for [Clojure](http://clojure.org) that targets JavaScript. It is designed to emit JavaScript code which is compatible with the advanced compilation mode of the [Google Closure](http://code.google.com/closure/) optimizing compiler. 9 | 10 | ## Releases and dependency information ## 11 | 12 | Latest stable release: 0.0-2665 13 | 14 | * [All released versions](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22clojurescript%22) 15 | 16 | [Leiningen](http://github.com/technomancy/leiningen/) dependency information: 17 | 18 | ``` 19 | [org.clojure/clojurescript "0.0-2665"] 20 | ``` 21 | 22 | [Maven](http://maven.apache.org) dependency information: 23 | 24 | ``` 25 | 26 | org.clojure 27 | clojurescript 28 | 0.0-2665 29 | 30 | ``` 31 | 32 | ## Getting Started ## 33 | 34 | * [Compare with JavaScript](http://himera.herokuapp.com/synonym.html) 35 | * [Try it online](http://himera.herokuapp.com/index.html) 36 | * Read the [Quick Start](https://github.com/clojure/clojurescript/wiki/Quick-Start) guide. 37 | * Read the [Documentation](https://github.com/clojure/clojurescript/wiki). 38 | * Try a [tutorial](https://github.com/clojure/clojurescript/wiki). 39 | * Look at the [Sample Applications](https://github.com/clojure/clojurescript/tree/master/samples). 40 | * [Companies using ClojureScript](https://github.com/clojure/clojurescript/wiki/Companies-Using-ClojureScript) 41 | 42 | ## Questions, Feedback? ## 43 | 44 | Please point all of your questions and feedback 45 | to the [Clojure mailing list](http://groups.google.com/group/clojure). There 46 | is also a community run [ClojureScript user mailing list](http://groups.google.com/group/clojurescript). The Jira bug/feature tracking application is located at . 47 | 48 | ## Developers Welcome ## 49 | 50 | ClojureScript operates under the same license as Clojure. All 51 | contributors must have a signed CA (Contributor's Agreement) and 52 | submit their patch via the appropriate channels. If you're interested 53 | in contributing to the project, please see the 54 | [contributing](http://clojure.org/contributing) page on 55 | [clojure.org](http://clojure.org). For more information about working 56 | on the compiler and testing check the 57 | [Developer section of the wiki](http://github.com/clojure/clojurescript/wiki/Developers). 58 | 59 | YourKit 60 | ---- 61 | 62 | 63 | 64 | YourKit has given an open source license for their profiler, greatly simplifying the profiling of ClojureScript performance. 65 | 66 | YourKit supports open source projects with its full-featured Java Profiler. 67 | YourKit, LLC is the creator of YourKit Java Profiler 68 | and YourKit .NET Profiler, 69 | innovative and intelligent tools for profiling Java and .NET applications. 70 | 71 | ## License ## 72 | 73 | Copyright (c) Rich Hickey. All rights reserved. The use and 74 | distribution terms for this software are covered by the Eclipse 75 | Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 76 | which can be found in the file epl-v10.html at the root of this 77 | distribution. By using this software in any fashion, you are 78 | agreeing to be bound by the terms of this license. You must 79 | not remove this notice, or any other, from this software. 80 | -------------------------------------------------------------------------------- /bin/cljsc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Compile a single cljs file or a directory of cljs files into a 4 | # single JavaScript file. 5 | 6 | if [ "$CLOJURESCRIPT_HOME" = "" ]; then 7 | CLOJURESCRIPT_HOME="`dirname $0`/.." 8 | fi 9 | 10 | CLJSC_CP='' 11 | for next in lib/*: src/clj: src/cljs: test/cljs; do 12 | CLJSC_CP="${CLJSC_CP}${CLOJURESCRIPT_HOME}/${next}" 13 | done 14 | 15 | if test "$#" -eq 0 16 | then 17 | echo 'Usage: cljsc ' 18 | echo ' cljsc "{:optimizations :advanced}"' 19 | else 20 | java -server -cp "$CLJSC_CP" clojure.main "$CLOJURESCRIPT_HOME/bin/cljsc.clj" "$@" 21 | fi 22 | -------------------------------------------------------------------------------- /bin/cljsc.bat: -------------------------------------------------------------------------------- 1 | 2 | @echo off 3 | setLocal EnableDelayedExpansion 4 | 5 | if "%CLOJURESCRIPT_HOME%" == "" set CLOJURESCRIPT_HOME=%~dp0..\ 6 | 7 | set CLASSPATH=%CLOJURESCRIPT_HOME%src\clj;%CLOJURESCRIPT_HOME%src\cljs" 8 | for /R "%CLOJURESCRIPT_HOME%\lib" %%a in (*.jar) do ( 9 | set CLASSPATH=!CLASSPATH!;%%a 10 | ) 11 | set CLASSPATH=!CLASSPATH!" 12 | 13 | if (%1) == () ( 14 | echo Usage: "cljsc > out.js" 15 | echo "cljsc {:optimiztions :advanced} > out.js" 16 | ) else ( 17 | java -server -cp "%CLASSPATH%" clojure.main "%CLOJURESCRIPT_HOME%\bin\cljsc.clj" %* 18 | ) 19 | -------------------------------------------------------------------------------- /bin/cljsc.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (require '[cljs.closure :as closure]) 10 | 11 | (defn transform-cl-args 12 | [args] 13 | (let [source (first args) 14 | opts-string (apply str (interpose " " (rest args))) 15 | options (when (> (count opts-string) 1) 16 | (try (read-string opts-string) 17 | (catch Exception e (println e))))] 18 | {:source source :options (merge {:output-to :print} options)})) 19 | 20 | (let [args (transform-cl-args *command-line-args*)] 21 | (closure/build (:source args) (:options args)) 22 | (.flush *out*) 23 | (shutdown-agents) 24 | (System/exit 0)) 25 | -------------------------------------------------------------------------------- /devnotes/README.org: -------------------------------------------------------------------------------- 1 | * ClojureScript 2 | - What: Clojure running on Javascript VMs 3 | - Why: Clojure rocks, Javascript reaches 4 | - When: Now! - a compiler exists, we need libraries and tool integration. Full day sessions 6/10 and 6/17 5 | - Where: In stealth mode 'here' at Clojure/core 6 | - How: ClojureScript -> ClojureScript-Compiler -> Javascript -> [Google-Closure-JS->JS-Compiler -> Optimized-Javascript] ->Browser/V8/Node/PhoneGap... 7 | - Who: You, if you're interested in: 8 | - How hand-written recursive descent compilers work (the ClojureScript compiler is about 1/6 the code of the CoffeeScript compiler) 9 | - Writing libraries using Clojure's latest type and polymorphism tools 10 | - How Clojure works - its data structures and abstractions 11 | - Extending the reach of Clojure 12 | - Google's industrial-strength JS tools 13 | - Investigating how powerful code-emitting tools can change the face 14 | of web and mobile development... 15 | * Getting Started 16 | - Clone the repo 17 | - cd clojurescript 18 | - run script/bootstrap 19 | - copy clojure.jar into /lib 20 | - script/repl will start a properly-classpathed repl 21 | * Starting the clojurescript repl 22 | - (require '[cljs.compiler :as comp]) 23 | - (def jse (comp/repl-env)) 24 | - (comp/repl jse) 25 | * Reading list 26 | - If you are interested in participating, please read: 27 | - [[http://www.amazon.com/Closure-Definitive-Guide-Michael-Bolin/dp/1449381871][Closure-Definitive-Guide-Michael-Bolin]] 28 | - and maybe: 29 | - [[http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742][JavaScript-Good-Parts-Douglas-Crockford]] 30 | - [[http://www.amazon.com/Performance-JavaScript-Faster-Application-Interfaces/dp/059680279X][Performance-JavaScript-Faster-Application-Interfaces]] 31 | - [[http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752][JavaScript-Patterns-Stoyan-Stefanov]] 32 | - Those looking to cram tonight can get the O'Reilly Closure book on kindle above or ebook directly: 33 | - [[http://oreilly.com/catalog/0636920001416/]] 34 | * More info 35 | [[https://github.com/relevance/clojurescript/wiki][Check the Wiki]] 36 | -------------------------------------------------------------------------------- /devnotes/bcrepl.org: -------------------------------------------------------------------------------- 1 | * ClojureScript browser connected REPL 2 | ** send cljs compiler output to the browser to be evaluated 3 | ** send results back to the command line process to be printed 4 | ** side effects happen in the browser 5 | ** abstract communication away using goog library 6 | *** Goog abstraction for websockets? Ideal! 7 | *** Polling? It will work everywhere. 8 | *** Ideally an abstraction over both that prefers websockets but doesn't fail and doesn't complain loudly. 9 | ** evaluation daemon for the browser 10 | ** launch browser 11 | ** transparent update of bound symbols? We should test. 12 | ** brepl has its own solution for deps, we'd like to tie into the ClojureScript dependency story 13 | ** require mechanisms are out; the source that forms the repl's environment will need to be updated and the page reloaded 14 | -------------------------------------------------------------------------------- /devnotes/day2.org: -------------------------------------------------------------------------------- 1 | * ClojureScript Day #2 2 | * Welcome Thortech! 3 | ** Eric, Frank and Tom 4 | *** Long time cohorts 5 | * Tips 6 | ** Don't define things in terms of undefined things 7 | *** someone else will just trip over later 8 | ** Test 9 | *** nil 10 | ** Encapsulate use of -methods in a single place 11 | ** Where's the global namespace? 12 | * Where are we at 13 | * Where are we going 14 | ** [[file:corelib.org][Core lib punchlist]] 15 | ** [[file:~/dev/clojurescript/todo.org][To do]] 16 | ** [[https://github.com/relevance/clojurescript/issues][Tickets]] 17 | * Release 1 18 | ** Make goog-compatible libs work 19 | ** Data structures 20 | *** work but are not optimal for large instances 21 | *** persistent guarantees 22 | ** seq library 23 | ** associative library 24 | ** indexed library 25 | ** atoms 26 | ** binding 27 | ** great tooling 28 | *** push button 29 | ** reader? 30 | *** print-read 31 | ** regex 32 | * Release 2 33 | ** DOM manipulation 34 | ** Can I use jQuery? 35 | ** bitops 36 | ** multimethods 37 | ** hierarchy 38 | ** reader + record support 39 | ** unchecked 40 | ** bitops 41 | ** print 42 | ** eventing value add 43 | ** DOM value add 44 | ** UI value add 45 | -------------------------------------------------------------------------------- /devnotes/talk.org: -------------------------------------------------------------------------------- 1 | * Title 2 | ** Clojure 3 | *** Rocks 4 | ** Javascript 5 | *** Reaches 6 | ** Announcing Clojure on Javascript 7 | *** ClojureScript 8 | * Problem statement 9 | ** Javascript is the only programmable technology in key target environments 10 | *** i.e. the browser 11 | *** nothing will change that for years to come 12 | ** and has the greatest reach in other key environments 13 | *** i.e. mobile 14 | ** Javascript (the language) is not very robust 15 | *** Fewer good parts than bad parts 16 | *** Much convention and discipline required to avoid headaches 17 | *** Conventions differ between shops, libs 18 | ** Ever increasing pressure to create richer applications in these environments 19 | *** requiring more, and larger, libraries 20 | **** ordinary minification doesn't scale up 21 | *** increasing requirements complexity 22 | **** can't add language or environment complexity on top 23 | * Rationale 24 | ** Clojure is arguably simpler, more powerful and more robust than JS 25 | ** JS VMs getting faster and more sophisticated 26 | ** Putting Clojure on JS empowers developers 27 | * Strategy 28 | ** Compile (a substantial subset of) Clojure to Javascript source 29 | ** Leverage best-of-breed JS approaches 30 | ** Look beyond the browser 31 | ** Non-objectives 32 | *** Complete Clojure 33 | *** Portable large applications 34 | *** Browser REPL demos etc 35 | ** Target is production applications 36 | * Tactics 37 | ** Clojure[Script] in Clojure 38 | *** Written in Clojure and itself 39 | ** Clojure on Closure 40 | *** Google's JS toolkit 41 | ** Clojure[Script] in Clojure 42 | ** Google Closure 43 | ** some subset of my gclosure lightning talk 44 | * Where we are at 45 | ** What's there? 46 | *** Compiler 47 | *** REPL 48 | *** All the primitives (that make sense) 49 | *** Arity overloading 50 | *** Macros 51 | *** Seqs, maps, vectors, sets 52 | **** and supporting library 53 | **** callable maps, vectors, sets 54 | *** Symbols and keywords 55 | *** deftypes and protocols 56 | *** all the core abstractions as protocols 57 | *** destructuring 58 | *** 2500 lines of core libs! 59 | *** clojure.string and .set .walk .zip 60 | *** regex 61 | *** reader? 62 | *** Full participation with Google Closure library 63 | **** ns mechanism maps to provide/require 64 | *** compile-file and compile-project 65 | ** What's not (yet)? 66 | *** Full collection persistence 67 | *** defrecord 68 | *** Multimethods 69 | *** Hierarchy 70 | *** Rich numerics 71 | *** Testing framework 72 | *** Misc core lib 73 | ** What won't be? 74 | *** things related to threads 75 | *** eval and runtime compilation 76 | *** structs, proxy, Java type stuff 77 | *** Runtime reification of: 78 | **** Vars 79 | **** Namespaces 80 | **** Protocols 81 | **** etc 82 | ** TBD 83 | *** optimizations 84 | **** chunks, transients 85 | *** agents (on webworkers?) 86 | *** unchecked 87 | ** What's different 88 | *** no runtime Vars 89 | *** some in-function subsetting 90 | **** e.g. satisfies? is a macro, can't be mapped/applied 91 | ** It's alpha 92 | * Where we are going 93 | ** This is Clojure's client story 94 | ** This is Clojure's mobile story 95 | ** This is Clojure's CLI scripting story 96 | * The Team thus far - Clojure/core and friends 97 | ** Aaron Bedra 98 | ** Alan Dipert 99 | ** Alex Redington 100 | ** Bobby Calderwood 101 | ** Brenton Ashworth 102 | ** Chris Houser 103 | ** Devin Walters 104 | ** Eric Thorsen 105 | ** Frank Failla 106 | ** Michael Fogus 107 | ** Jonathan Clagett 108 | ** Jess Martin 109 | ** Luke VanderHart 110 | ** Chris Redinger 111 | ** Stuart Halloway 112 | ** Stuart Sierra 113 | ** Tom Hickey 114 | * Participating 115 | ** This is a Clojure dev project 116 | *** all with Clojure CAs welcome to participate 117 | ** The Friday invite 118 | ** The Conj 119 | * Demo 120 | ** REPL 121 | ** Compilation 122 | ** Web app 123 | ** CLI app? 124 | * Q & A 125 | 126 | 127 | -------------------------------------------------------------------------------- /devnotes/testing: -------------------------------------------------------------------------------- 1 | Definitely a work-in-progress. 2 | 3 | To run tests before you commit: 4 | 5 | script/test 6 | 7 | To add tests: 8 | 9 | * Create test fiels in the test/cljs directory. 10 | * Write fns that throw an exception on failure. 11 | * Call those fns from test/cljs/cljs/test_runner.cljs 12 | 13 | 14 | -------------------------------------------------------------------------------- /devnotes/todo.org: -------------------------------------------------------------------------------- 1 | #+TODO: TODO IN-PROGRESS REVIEW DONE 2 | * The near term tasks 3 | * Compiler 4 | ** IN-PROGRESS throw/try/catch/finally :@stuarthalloway: 5 | * Data structures 6 | ** IN-PROGRESS keyword :@levand: 7 | *** requires interning strategy 8 | **** possibly compiler support for same 9 | *** string starting with noncharacter code 10 | **** \uFFFE and \uFFFF are guaranteed noncharacters 11 | **** use as prefix for keywords and symbols 12 | **** must test in predicates string? symbol? keyword? 13 | ** IN-PROGRESS symbol :@levand: 14 | *** string starting with noncharacter code 15 | ** DONE cons cell/list 16 | ** DONE map 17 | *** first cut COW, string uniqueness required 18 | ** DONE vector 19 | *** first cut, COW, internal array 20 | ** TODO numbers 21 | *** js native number is our double 22 | *** goog.math.Long? 23 | **** building Long objects defeats fixnum support in JS VMs 24 | **** but they are 32-bit - some type bits 25 | * Abstractions 26 | ** TODO Clojure's interfaces 27 | *** we don't need all of them 28 | Associative 29 | Counted 30 | Fn 31 | IBlockingDeref 32 | IChunk 33 | IChunkedSeq 34 | IDeref 35 | IEditableCollection 36 | IFn 37 | IKeywordLookup 38 | ILookup 39 | ILookupSite 40 | ILookupThunk 41 | IMapEntry 42 | IMeta 43 | Indexed 44 | IndexedSeq 45 | IObj 46 | IPending 47 | IPersistentCollection 48 | IPersistentList 49 | IPersistentMap 50 | IPersistentSet 51 | IPersistentStack 52 | IPersistentVector 53 | IProxy 54 | IRecord 55 | IReduce 56 | IRef 57 | IReference 58 | ISeq 59 | ITransientAssociative 60 | ITransientCollection 61 | ITransientMap 62 | ITransientSet 63 | ITransientVector 64 | IType 65 | MapEquivalence 66 | Named 67 | Reversible 68 | Seqable 69 | Sequential 70 | Settable 71 | Sorted 72 | ** Naming convention for protocols? 73 | *** IBlah 74 | ** TODO equality and hashing 75 | *** investigate gclosure and GWT 76 | ** TODO seqable 77 | ** TODO collection 78 | ** TODO counted 79 | ** DONE seq 80 | ** TODO lookup 81 | ** TODO associative 82 | ** TODO indexed 83 | ** TODO map 84 | ** TODO set 85 | ** TODO vector 86 | ** TODO deref 87 | ** TODO metadata 88 | * Runtime Lib 89 | ** key missing macros 90 | *** binding 91 | **** single threaded 92 | **** save, set!, finally restore 93 | **** deps: try/finally primitives in compiler 94 | *** dotimes 95 | ** math ops 96 | *** intrinsify built-ins 97 | *** handle variadic 98 | ** core.cljs! 99 | *** crank through core.clj 100 | *** see [[file:docs/corelib.org][docs/corelib.org]] 101 | * Tools 102 | ** getting set up story 103 | *** gclosure library 104 | *** gclosure compiler 105 | *** V8 106 | **** optional for now? 107 | ** DONE REPL 108 | *** there's a ticket for this 109 | ** Integration of gclosure library 110 | *** how do we reference/load? 111 | **** REPL runtime behavior of provide/require 112 | *** versioning issues 113 | **** just SVN revs 114 | **** how to bind to version 115 | ** Testing 116 | *** anything good in gclosure? 117 | ** Build 118 | *** deps 119 | *** glcosure compiler 120 | **** invocation via API gives most control 121 | **** but deps a Python thingy 122 | -------------------------------------------------------------------------------- /feature-macros-demo/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: deps demo 2 | 3 | bin/boot: 4 | mkdir -p bin 5 | wget -O bin/boot https://github.com/boot-clj/boot/releases/download/2.0.0-rc8/boot.sh 6 | chmod 0755 bin/boot 7 | 8 | ../pom.xml: 9 | (cd ../ && ./script/bootstrap && ./script/clean && ./script/build) 10 | 11 | .deps.time: bin/boot ../pom.xml 12 | touch .deps.time 13 | 14 | deps: .deps.time 15 | 16 | demo: 17 | ./bin/boot demo 18 | -------------------------------------------------------------------------------- /feature-macros-demo/boot-shim.clj: -------------------------------------------------------------------------------- 1 | (in-ns 'clojure.core) 2 | 3 | (def ^:dynamic *platform* :clj) 4 | 5 | (defmacro ns+ [& clauses] 6 | (let [require-ops #{:refer-clojure :require :use :import :load 7 | :gen-class :require-macros :use-macros} 8 | this-platform? #(cond (or (not (seq? %)) (require-ops (first %))) % 9 | (= *platform* (first %)) (second %))] 10 | `(~'ns ~@(keep this-platform? clauses)))) 11 | 12 | (defmacro case-platform [& pairs] 13 | (get (apply hash-map pairs) *platform* 14 | `(throw (ex-info "Unsupported platform" {:platform *platform*})))) 15 | 16 | (alter-var-root #'load #(fn [& xs] (binding [*platform* :clj] (apply % xs)))) 17 | -------------------------------------------------------------------------------- /feature-macros-demo/boot.properties: -------------------------------------------------------------------------------- 1 | #https://github.com/boot-clj/boot 2 | #Tue Jan 20 13:31:27 EST 2015 3 | BOOT_CLOJURE_VERSION=1.6.0 4 | BOOT_VERSION=2.0.0-rc8 5 | -------------------------------------------------------------------------------- /feature-macros-demo/build.boot: -------------------------------------------------------------------------------- 1 | (set-env! 2 | :source-paths #{"src"} 3 | :resource-paths #{"html"} 4 | :dependencies '[[pathetic "0.5.0"] 5 | [org.clojure/clojurescript "0.0-2694"] 6 | [adzerk/boot-cljs "0.0-2629-8"]]) 7 | 8 | (require '[demo.core :as core] 9 | '[clojure.java.io :as io] 10 | '[adzerk.boot-cljs :refer [cljs]] 11 | '[boot.from.io.aviso.ansi :refer :all]) 12 | 13 | (defn say [msg] 14 | (with-pre-wrap fs (info (green (str msg "\n"))) fs)) 15 | 16 | (deftask run 17 | "Run CLJ demo code." 18 | [] 19 | (with-pre-wrap fs (core/-main) fs)) 20 | 21 | (deftask demo 22 | "Compile CLJS and run CLJ demos." 23 | [] 24 | (comp 25 | (say "** COMPILING CLJS DEMO **") 26 | (cljs) 27 | (say (format "file://%s/target/index.html" (System/getProperty "user.dir"))) 28 | (say "** RUNNING CLJ DEMO **") 29 | (run) 30 | (say "** TRY FEATURE MACROS IN THE REPL **") 31 | (repl))) 32 | -------------------------------------------------------------------------------- /feature-macros-demo/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | feature macros demo 5 | 6 | 7 |
8 |

feature macros demo

9 | source code 10 |

Please open your JacaScript console to see the log messages.

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /feature-macros-demo/src/cemerick/url.clj: -------------------------------------------------------------------------------- 1 | (ns+ cemerick.url 2 | (:clj (:import (java.net URLEncoder URLDecoder))) 3 | (:clj (:require [pathetic.core :as pathetic] 4 | [clojure.string :as string])) 5 | (:cljs (:require-macros [clojure.core :refer [some-> some->>]])) 6 | (:cljs (:require [pathetic.core :as pathetic] 7 | [clojure.string :as string] 8 | [goog.Uri :as uri]))) 9 | 10 | (case-platform 11 | :clj 12 | (defn url-encode 13 | [string] 14 | (some-> string str (URLEncoder/encode "UTF-8") (.replace "+" "%20"))) 15 | 16 | :cljs 17 | (defn url-encode 18 | [string] 19 | (some-> string str (js/encodeURIComponent) (.replace "+" "%20")))) 20 | 21 | (case-platform 22 | :clj 23 | (defn url-decode 24 | ([string] (url-decode string "UTF-8")) 25 | ([string encoding] 26 | (some-> string str (URLDecoder/decode encoding)))) 27 | 28 | :cljs 29 | (defn url-decode 30 | [string] 31 | (some-> string str (js/decodeURIComponent)))) 32 | 33 | (defn map->query 34 | [m] 35 | (some->> (seq m) 36 | sort ; sorting makes testing a lot easier :-) 37 | (map (fn [[k v]] 38 | [(url-encode (name k)) 39 | "=" 40 | (url-encode (str v))])) 41 | (interpose "&") 42 | flatten 43 | (apply str))) 44 | 45 | (defn split-param [param] 46 | (-> 47 | (string/split param #"=") 48 | (concat (repeat "")) 49 | (->> 50 | (take 2)))) 51 | 52 | (defn query->map 53 | [qstr] 54 | (when (not (string/blank? qstr)) 55 | (some->> (string/split qstr #"&") 56 | seq 57 | (mapcat split-param) 58 | (map url-decode) 59 | (apply hash-map)))) 60 | 61 | (defn- port-str 62 | [protocol port] 63 | (when (and (not= nil port) 64 | (not= -1 port) 65 | (not (and (== port 80) (= protocol "http"))) 66 | (not (and (== port 443) (= protocol "https")))) 67 | (str ":" port))) 68 | 69 | (defn- url-creds 70 | [username password] 71 | (when username 72 | (str username ":" password))) 73 | 74 | (defrecord URL 75 | [protocol username password host port path query anchor] 76 | Object 77 | (toString [this] 78 | (let [creds (url-creds username password)] 79 | (str protocol "://" 80 | creds 81 | (when creds \@) 82 | host 83 | (port-str protocol port) 84 | path 85 | (when (seq query) (str \? (if (string? query) 86 | query 87 | (map->query query)))) 88 | (when anchor (str \# anchor)))))) 89 | 90 | (case-platform 91 | :clj 92 | (defn- url* 93 | [url] 94 | (let [url (java.net.URL. url) 95 | [user pass] (string/split (or (.getUserInfo url) "") #":" 2)] 96 | (URL. (.toLowerCase (.getProtocol url)) 97 | (and (seq user) user) 98 | (and (seq pass) pass) 99 | (.getHost url) 100 | (.getPort url) 101 | (pathetic/normalize (.getPath url)) 102 | (query->map (.getQuery url)) 103 | (.getRef url)))) 104 | 105 | :cljs 106 | (defn translate-default 107 | [s old-default new-default] 108 | (if (= s old-default) 109 | new-default 110 | s))) 111 | 112 | (case-platform 113 | :clj nil 114 | :cljs 115 | (defn- url* 116 | [url] 117 | (let [url (goog.Uri. url) 118 | [user pass] (string/split (or (.getUserInfo url) "") #":" 2)] 119 | (URL. (.getScheme url) 120 | (and (seq user) user) 121 | (and (seq pass) pass) 122 | (.getDomain url) 123 | (translate-default (.getPort url) nil -1) 124 | (pathetic/normalize (.getPath url)) 125 | (query->map (translate-default (.getQuery url) "" nil)) 126 | (translate-default (.getFragment url) "" nil))))) 127 | 128 | (defn url 129 | "Returns a new URL record for the given url string(s). 130 | 131 | The first argument must be a base url — either a complete url string, or 132 | a pre-existing URL record instance that will serve as the basis for the new 133 | URL. Any additional arguments must be strings, which are interpreted as 134 | relative paths that are successively resolved against the base url's path 135 | to construct the final :path in the returned URL record. 136 | 137 | This function does not perform any url-encoding. Use `url-encode` to encode 138 | URL path segments as desired before passing them into this fn." 139 | ([url] 140 | (if (instance? URL url) 141 | url 142 | (url* url))) 143 | ([base-url & path-segments] 144 | (let [base-url (if (instance? URL base-url) base-url (url base-url))] 145 | (assoc base-url :path (pathetic/normalize (reduce pathetic/resolve 146 | (:path base-url) 147 | path-segments)))))) 148 | 149 | -------------------------------------------------------------------------------- /feature-macros-demo/src/cemerick/url.cljs: -------------------------------------------------------------------------------- 1 | url.clj -------------------------------------------------------------------------------- /feature-macros-demo/src/demo.cljs.edn: -------------------------------------------------------------------------------- 1 | {:require [demo.core] 2 | :init-fns [demo.core/-main]} 3 | -------------------------------------------------------------------------------- /feature-macros-demo/src/demo/core.clj: -------------------------------------------------------------------------------- 1 | (ns+ demo.core 2 | (:clj (:require [cemerick.url :as url] 3 | [demo.util :as util])) 4 | (:cljs (:require [cemerick.url :as url] 5 | [demo.util :as util :include-macros true]))) 6 | 7 | (def url 8 | {:protocol "https" 9 | :host "github.com" 10 | :path "/feature-macros/clojurescript"}) 11 | 12 | (defn -main [& _] 13 | (util/log-err (util/format "hello world: %s" (url/map->URL url)))) 14 | -------------------------------------------------------------------------------- /feature-macros-demo/src/demo/core.cljs: -------------------------------------------------------------------------------- 1 | core.clj -------------------------------------------------------------------------------- /feature-macros-demo/src/demo/util.clj: -------------------------------------------------------------------------------- 1 | (ns+ demo.util 2 | (:clj (:refer-clojure :exclude [format])) 3 | (:cljs (:require [goog.string :as gstring] 4 | [goog.string.format]))) 5 | 6 | (case-platform 7 | :cljs nil 8 | :clj (defmacro log-err [message] 9 | (condp = *platform* 10 | :clj `(.println (System/-err) ~message) 11 | :cljs `(.warn js/console ~message)))) 12 | 13 | (defn format [fmt & args] 14 | (case-platform 15 | :clj (apply clojure.core/format fmt args) 16 | :cljs (apply gstring/format fmt args))) 17 | 18 | -------------------------------------------------------------------------------- /feature-macros-demo/src/demo/util.cljs: -------------------------------------------------------------------------------- 1 | util.clj -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject org.clojure/clojurescript "0.0-SNAPSHOT" 2 | :description "ClojureScript compiler and core runtime library" 3 | :parent [org.clojure/pom.contrib "0.1.2"] 4 | :url "https://github.com/clojure/clojurescript" 5 | :license {:name "Eclipse Public License" 6 | :url "http://www.eclipse.org/legal/epl-v10.html"} 7 | :jvm-opts ^:replace ["-Xmx512m" "-server"] 8 | :source-paths ["src/clj"] 9 | :resource-paths ["src/cljs"] 10 | :test-paths ["test/clj"] 11 | :dependencies [[org.clojure/clojure "1.6.0"] 12 | [org.clojure/data.json "0.2.3"] 13 | [org.clojure/tools.reader "0.8.10"] 14 | [org.clojure/google-closure-library "0.0-20140718-946a7d39"] 15 | [com.google.javascript/closure-compiler "v20140625"] 16 | [org.mozilla/rhino "1.7R4"]] 17 | :profiles {:1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} 18 | :1.6 {:dependencies [[org.clojure/clojure "1.6.0-master-SNAPSHOT"]]}} 19 | :aliases {"test-all" ["with-profile" "test,1.5:test,1.6" "test"] 20 | "check-all" ["with-profile" "1.5:1.6" "check"]} 21 | :min-lein-version "2.0.0") 22 | -------------------------------------------------------------------------------- /samples/dom/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | dom.js -------------------------------------------------------------------------------- /samples/dom/src/dom/test.cljs: -------------------------------------------------------------------------------- 1 | (ns dom.test 2 | (:require [clojure.browser.event :as event] 3 | [clojure.browser.dom :as dom])) 4 | 5 | (defn log [& args] 6 | (.log js/console (apply pr-str args))) 7 | 8 | (defn log-obj [obj] 9 | (.log js/console obj)) 10 | 11 | (defn log-listener-count [] 12 | (log "listener count: " (event/total-listener-count))) 13 | 14 | (def source (dom/get-element "source")) 15 | (def destination (dom/get-element "destination")) 16 | 17 | (dom/append source 18 | (dom/element "Testing me ") 19 | (dom/element "out!")) 20 | 21 | (def success-count (atom 0)) 22 | 23 | (log-listener-count) 24 | 25 | (event/listen source 26 | :click 27 | (fn [e] 28 | (let [i (swap! success-count inc) 29 | e (dom/element :li 30 | {:id "testing" 31 | :class "test me out please"} 32 | "It worked!")] 33 | (log-obj e) 34 | (log i) 35 | (dom/append destination 36 | e)))) 37 | 38 | (log-obj (dom/element "Text node")) 39 | (log-obj (dom/element :li)) 40 | (log-obj (dom/element :li {:class "foo"})) 41 | (log-obj (dom/element :li {:class "bar"} "text node")) 42 | (log-obj (dom/element [:ul [:li :li :li]])) 43 | (log-obj (dom/element :ul [:li :li :li])) 44 | (log-obj (dom/element :li {} [:ul {} [:li :li :li]])) 45 | (log-obj (dom/element [:li {:class "baz"} [:li {:class "quux"}]])) 46 | 47 | (log-obj source) 48 | (log-listener-count) -------------------------------------------------------------------------------- /samples/dom/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | DOM testing 12 | 13 | 14 | 17 | 18 | 19 | 20 |
21 |
    22 | 23 | 24 | 25 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/hello-js/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | hello*.js 3 | -------------------------------------------------------------------------------- /samples/hello-js/README.md: -------------------------------------------------------------------------------- 1 | Simple ClojureScript Project Example Using an External JavaScript Library 2 | 3 | One-time Setup 4 | ============== 5 | 6 | - Create a CLOJURESCRIPT_HOME environment variable which points to the 7 | ClojureScript root directory. 8 | 9 | - If you have not already done so, execute 10 | 11 | $CLOJURESCRIPT_HOME/script/bootstrap 12 | 13 | - Add $CLOJURESCRIPT_HOME/bin to your PATH. 14 | 15 | 16 | Simple external JavaScript file 17 | =============================== 18 | 19 | 20 | 21 | Run in Development Mode 22 | ----------------------- 23 | 24 | Development mode allows for each file to be loaded in a separate script tag so 25 | that errors can be easily tracked to the offending file. 26 | 27 | cljsc src > hello-js.js 28 | 29 | After running the above command, open hello-js-dev.html. Notice that each required 30 | JavaScript file has been loaded in its most readable form. 31 | 32 | Run Optimized JavaScript 33 | ------------------------ 34 | 35 | Once an application is ready for production, a single optimized file can be produced. 36 | 37 | cljsc src {:optimizations :advanced} > hello-js.js 38 | 39 | After running the above command, open hello-js.html to view the result. 40 | 41 | 42 | Using an externed JavaScript file 43 | ================================= 44 | 45 | To see how external calls are optimized away, execute the following: 46 | 47 | cljsc src '{:optimizations :advanced :output-to "hello-extern.js"}' 48 | 49 | After running the above command, open hello-extern.html to view the result. You should see nothing and possibly a JavaScript error. The solution is to compile the ClojureScript source with a referred externs file as follows: 50 | 51 | cljsc src '{:optimizations :advanced :output-to "hello-extern.js" :externs ["externs.js"]}' 52 | 53 | Again after running the above command, open hello-extern.html to view the result. You should see an alert box. 54 | -------------------------------------------------------------------------------- /samples/hello-js/externed-lib.js: -------------------------------------------------------------------------------- 1 | external = {}; 2 | 3 | external.lib = { 4 | send_alert : function (msg) { 5 | alert("Sending Alert via " + msg + "!"); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /samples/hello-js/externs.js: -------------------------------------------------------------------------------- 1 | var external = {}; 2 | external.lib = {}; 3 | external.lib.send_alert = function() {}; 4 | -------------------------------------------------------------------------------- /samples/hello-js/hello-extern.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello Externed JavaScript Library 4 | 5 | 6 |

    Hello Externed JavaScript Library!

    7 | 8 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /samples/hello-js/hello-js-dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello External JavaScript Library 4 | 5 | 6 |

    Hello External JavaScript Library!

    7 | 8 | 9 | 10 | 11 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /samples/hello-js/hello-js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello External JavaScript Library 4 | 5 | 6 |

    Hello External JavaScript Library!

    7 | 8 | 9 | 10 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /samples/hello-js/my-external-lib.js: -------------------------------------------------------------------------------- 1 | function send_alert(msg) { 2 | alert("Sending Alert via " + msg + "!"); 3 | }; 4 | -------------------------------------------------------------------------------- /samples/hello-js/src/hello-js/core.cljs: -------------------------------------------------------------------------------- 1 | (ns hello-js.core) 2 | 3 | (defn ^:export popup-msg 4 | [msg] 5 | (js/send_alert msg)) 6 | 7 | (popup-msg "ClojureScript calling a global function defined in an external JavaScript library") 8 | 9 | (popup-msg (str "ClojureScript: the time is now " (js/Date.))) 10 | -------------------------------------------------------------------------------- /samples/hello-js/src/hello-js/extern-example.cljs: -------------------------------------------------------------------------------- 1 | (ns hello.extern-example) 2 | 3 | (defn ^:export foo [] 42) 4 | 5 | (external.lib/send_alert "ClojureScript calling a function defined in an externed JavaScript library") 6 | -------------------------------------------------------------------------------- /samples/hello/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | hello.js 3 | -------------------------------------------------------------------------------- /samples/hello/README.md: -------------------------------------------------------------------------------- 1 | Simple ClojureScript Project Example. 2 | 3 | One-time Setup 4 | ============== 5 | 6 | - Create a CLOJURESCRIPT_HOME environment variable which points to the 7 | ClojureScript root directory. 8 | 9 | - If you have not already done so, execute 10 | 11 | $CLOJURESCRIPT_HOME/script/bootstrap 12 | 13 | - Add $CLOJURESCRIPT_HOME/bin to your PATH. 14 | 15 | Run in Development Mode 16 | ======================= 17 | 18 | Development mode allows for each file to be loaded in a separate script tag so 19 | that errors can be easily tracked to the offending file. 20 | 21 | cljsc src > hello.js 22 | 23 | After running the above command, open hello-dev.html. Notice that each required 24 | JavaScript file has been loaded in its most readable form. 25 | 26 | Run Optimized JavaScript 27 | ======================== 28 | 29 | Once an application is ready for production, a single optimized file can be produced. 30 | 31 | cljsc src {:optimizations :advanced} > hello.js 32 | 33 | After running the above command, open hello.html to view the result. 34 | 35 | -------------------------------------------------------------------------------- /samples/hello/hello-dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello ClojureScript 4 | 5 | 6 |

    Hello ClojureScript!

    7 | 8 | 9 | 10 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /samples/hello/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello ClojureScript 4 | 5 | 6 |

    Hello ClojureScript!

    7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/hello/src/hello/core.cljs: -------------------------------------------------------------------------------- 1 | (ns hello.core 2 | (:require [hello.foo.bar :as bar])) 3 | 4 | (defn ^{:export greet} greet [n] 5 | (str "Hello " n)) 6 | 7 | (defn ^:export sum [xs] 8 | (bar/sum xs)) 9 | 10 | (defn ^:export let-works? [day month year] 11 | (let [hour (first day) 12 | minutes (first hour) 13 | seconds (last hour)] 14 | (.log js/console "Date: " year month day) 15 | (str year month day hour minutes seconds))) 16 | 17 | (defn bailey [proton neutron electron & comedies] 18 | (apply + proton neutron electron) 19 | (map identity comedies)) 20 | 21 | (defn videotape [& rainbows] 22 | (map :params rainbows)) 23 | -------------------------------------------------------------------------------- /samples/hello/src/hello/foo/bar.cljs: -------------------------------------------------------------------------------- 1 | (ns hello.foo.bar) 2 | 3 | (defn sum [xs] 4 | (reduce + 0 xs)) 5 | -------------------------------------------------------------------------------- /samples/nodehello.cljs: -------------------------------------------------------------------------------- 1 | (ns nodehello 2 | (:require [cljs.nodejs :as nodejs])) 3 | 4 | (defn -main [& args] 5 | (println (apply str (map [\space "world" "hello"] [2 0 1])))) 6 | 7 | (nodejs/enable-util-print!) 8 | (set! *main-cli-fn* -main) 9 | 10 | (comment 11 | ; Compile this using a command line like: 12 | 13 | CLOJURESCRIPT_HOME=".../clojurescript/" \ 14 | bin/cljsc samples/nodehello.cljs {:target :nodejs} \ 15 | > out/nodehello.js 16 | 17 | ; Then run using: 18 | nodejs out/nodehello.js 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /samples/nodels.cljs: -------------------------------------------------------------------------------- 1 | ; This one doesn't yet work with :optimizations :advanced 2 | (ns nodels 3 | (:require [cljs.nodejs :as nodejs])) 4 | 5 | (def fs (nodejs/require "fs")) 6 | (def path (nodejs/require "path")) 7 | 8 | (defn file-seq [dir] 9 | (tree-seq 10 | (fn [f] (.isDirectory (.statSync fs f) ())) 11 | (fn [d] (map #(.join path d %) (.readdirSync fs d))) 12 | dir)) 13 | 14 | (defn -main [& paths] 15 | (dorun (map println (mapcat file-seq paths)))) 16 | 17 | (nodejs/enable-util-print!) 18 | (set! *main-cli-fn* -main) 19 | -------------------------------------------------------------------------------- /samples/repl/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | main.js 3 | -------------------------------------------------------------------------------- /samples/repl/README.md: -------------------------------------------------------------------------------- 1 | # ClojureScript REPL Examples 2 | 3 | The ClojureScript REPL has been updated to work with multiple 4 | JavaScript evaluation environments. This readme and the example code 5 | in this project show how to use the new REPL. There are now two 6 | implemented environments: Rhino and the browser. 7 | 8 | ## Using the new REPL 9 | 10 | There are currently four steps in starting a ClojureScript REPL. 11 | 12 | 1. require cljs.repl 13 | 2. require the namespace which implements the desired evaluation environment 14 | 3. create a new evaluation environment 15 | 4. start the REPL with the created environment 16 | 17 | ## Evaluating with Rhino 18 | 19 | ```clj 20 | (require '[cljs.repl :as repl]) 21 | (require '[cljs.repl.rhino :as rhino]) 22 | (def env (rhino/repl-env)) 23 | (repl/repl env) 24 | ``` 25 | 26 | ## Evaluating in the Browser 27 | 28 | A browser-connected REPL works in much the same way as a normal REPL: 29 | forms are read from the console, evaluated and return values are 30 | printed. A major and useful difference from normal REPL usage is that 31 | all side-effects occur in the browser. You can show alerts, manipulate 32 | the dom and interact with running applications. 33 | 34 | The main benefit of using the browser as an evaluation environment is 35 | that the REPL is no longer limited to non-browser code. You get all 36 | the benefits of a REPL with all of your code. 37 | 38 | The example below shows how to start a browser-connected REPL with an 39 | empty project. The same technique can be used to integrate a REPL into 40 | an existing project. In the future there may be an easier way to start 41 | a browser-connected REPL without a project. 42 | 43 | ### Building 44 | 45 | This sample project contains an HTML file and single ClojureScript 46 | file which establishes the connection to the REPL from the 47 | browser. These are currently the minimum requirements for starting a 48 | browser-connected REPL. 49 | 50 | To build the project, launch a Clojure REPL from this folder 51 | 52 | ```bash 53 | cd samples/repl 54 | ../../script/repl 55 | ``` 56 | 57 | and evaluate the following forms: 58 | 59 | ```clj 60 | (require '[cljs.closure :as cljsc]) 61 | (def opts {:output-to "main.js" :output-dir "out"}) 62 | (cljsc/build "src" opts) 63 | ``` 64 | 65 | ### Starting the REPL and connecting to the browser 66 | 67 | Start the REPL using the browser as the evaluator (do it in "samples/repl"): 68 | 69 | ```clj 70 | (require '[cljs.repl :as repl]) 71 | (require '[cljs.repl.browser :as browser]) 72 | (def env (browser/repl-env)) 73 | (repl/repl env) 74 | ``` 75 | 76 | Open http://localhost:9000/ in a browser. When this page is loaded it will connect 77 | to the REPL. Alternatively you can serve index.html from your own local webserver. 78 | 79 | ### Try it out 80 | 81 | ```clj 82 | ;; Evaluate some basic forms. 83 | (+ 1 1) 84 | {:a :b} 85 | "hello" 86 | (reduce + [1 2 3 4 5]) 87 | (js/alert "Hello World!") 88 | 89 | ;; Load a file, and use it. 90 | (load-file "clojure/string.cljs") 91 | (clojure.string/reverse "Hello") 92 | 93 | ;; Define functions and call them. 94 | (defn sum [coll] (reduce + coll)) 95 | (sum [2 2 2 2]) 96 | 97 | ;; Create dom elements. 98 | (ns dom.testing (:require [clojure.browser.dom :as dom])) 99 | (dom/append (dom/get-element "content") 100 | (dom/element "Hello World!")) 101 | ``` 102 | -------------------------------------------------------------------------------- /samples/repl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Browser-connected REPL 12 | 13 | 14 | 17 | 18 | 19 | 20 |
    21 | 22 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /samples/repl/src/repl/test.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns repl.test 10 | (:require [clojure.browser.repl :as repl] 11 | ;[clojure.reflect :as reflect] 12 | )) 13 | 14 | (repl/connect "http://localhost:9000/repl") 15 | 16 | (comment 17 | 18 | ;; Note: If you would like for the compiler to be aware of 19 | ;; everything in a project then delete the 'out' directory before 20 | ;; calling build. This will force the compiler to compile the whole 21 | ;; project. 22 | 23 | ;; Compile this project to JavaScript 24 | (use 'cljs.closure) 25 | (def opts {:output-to "samples/repl/main.js" 26 | :output-dir "samples/repl/out"}) 27 | (build "samples/repl/src" opts) 28 | 29 | ;; Start REPL 30 | (do (require '[cljs.repl :as repl]) 31 | (require '[cljs.repl.browser :as browser]) 32 | (def env (browser/repl-env)) 33 | (repl/repl env)) 34 | 35 | ;; Open http://localhost:9000/ in a browser. When this page is loaded 36 | ;; it will connect to the REPL. Alternatively you can serve index.html 37 | ;; from your own local webserver. 38 | 39 | ;; Evaluate some basic forms 40 | (+ 1 1) 41 | (string-print "hello") 42 | (prn "foo") 43 | (prn {:a :b}) 44 | (println "hello") 45 | (doseq [next (range 20)] (println next)) 46 | {:a :b} 47 | "hello" 48 | (reduce + [1 2 3 4 5]) 49 | (time (reduce + (range 10000))) 50 | (js/alert "Hello World!") 51 | 52 | (load-file "clojure/string.cljs") 53 | (clojure.string/reverse "Hello") 54 | 55 | (defn sum [coll] (reduce + coll)) 56 | (sum [2 2 2 2]) 57 | 58 | ;; Create dom elements. 59 | (ns dom.testing (:require [clojure.browser.dom :as dom])) 60 | (dom/append (dom/get-element "content") 61 | (dom/element "Hello World!")) 62 | 63 | ;; Load something we haven't used yet 64 | (ns test.crypt 65 | (:require [goog.crypt :as c])) 66 | (c/stringToByteArray "ClojureScript") 67 | 68 | (load-namespace 'goog.date.Date) 69 | (goog.date.Date.) 70 | 71 | (ns test.color (:require [goog.color :as c])) 72 | (js->clj (c/parse "#000000")) 73 | 74 | ) 75 | -------------------------------------------------------------------------------- /samples/twitterbuzz/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | twitterbuzz.js 3 | -------------------------------------------------------------------------------- /samples/twitterbuzz/README.md: -------------------------------------------------------------------------------- 1 | # ClojureScript "TwitterBuzz" Demo 2 | 3 | ## One-time Setup 4 | 5 | See https://github.com/clojure/clojurescript/wiki/Quick-Start 6 | 7 | ## Run in Development Mode 8 | 9 | Compile the demo: 10 | 11 | cljsc src > twitterbuzz.js 12 | 13 | After running the above command, open index.html. 14 | 15 | ## Compile in Development Mode with the REPL (Faster) 16 | 17 | * Run `script/repl` 18 | * To run it from Emacs, `C-x d` and nav to the `clojurescript` directory 19 | * `M-x set-variable inferior-lisp-program` 20 | * Set to `"script/repl"` 21 | * `M-x run-lisp` 22 | 23 | * Once the REPL is running, evaluate: 24 | 25 | (use 'cljs.closure) 26 | (def opts {:output-to "samples/twitterbuzz/twitterbuzz.js" :output-dir "samples/twitterbuzz/out"}) 27 | 28 | (build "samples/twitterbuzz/src" opts) 29 | 30 | The reason we set the `:output-dir` is because the `index.html` script tag is specifically pointing to that directory. 31 | 32 | * See `cljs.closure` source for more compilation examples. 33 | 34 | ## Compile in Advanced Mode 35 | 36 | `cljsc` can be run with a Clojure map of compiler options. To compile using `cljsc` and Closure Compiler's "advanced" optimization setting: 37 | 38 | cljsc src '{:optimizations :advanced}' > twitterbuzz.js 39 | 40 | Because advanced mode results in only one `.js` file, `twitterbuzz.js`, only one ` 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /samples/twitterbuzz/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | TwitterBuzz: A ClojureScript Demo 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 |
    28 |
    29 |

    TwitterBuzz: A ClojureScript Demo

    30 |
    Learn more: 31 | ClojureScript | 32 | Documentation | 33 | Source Code 35 |
    36 |

    Clojure

    37 |
    38 |
    39 | 40 |
    41 |
    42 | 43 | 44 | Not Connected 45 |
    46 |
    47 | 48 |
    49 |
    50 | 51 |
    52 |
    53 | 54 |
    55 |

    Leaderboard

    56 |
    57 |
    58 |
    59 | 60 |
    61 |

    Timeline

    62 |
    63 |
    64 |
    65 | 66 |
    67 |
    68 | 69 |
    70 |
    71 | 72 | 75 | 76 | 77 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /samples/twitterbuzz/reset.css: -------------------------------------------------------------------------------- 1 | /* Eric Meyer's Reset Reloaded */ 2 | html, body, div, span, applet, object, iframe, 3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 4 | a, abbr, acronym, address, big, cite, code, 5 | del, dfn, em, font, img, ins, kbd, q, s, samp, 6 | small, strike, strong, sub, sup, tt, var, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td { 10 | margin: 0; 11 | padding: 0; 12 | border: 0; 13 | outline: 0; 14 | font-weight: inherit; 15 | font-style: inherit; 16 | font-size: 100%; 17 | font-family: inherit; 18 | vertical-align: baseline; 19 | } 20 | /* remember to define focus styles! */ 21 | :focus { 22 | outline: 0; 23 | } 24 | body { 25 | line-height: 1; 26 | color: black; 27 | background: white; 28 | } 29 | ol, ul { 30 | list-style: none; 31 | } 32 | /* tables still need 'cellspacing="0"' in the markup */ 33 | table { 34 | border-collapse: separate; 35 | border-spacing: 0; 36 | } 37 | caption, th, td { 38 | text-align: left; 39 | font-weight: normal; 40 | } 41 | blockquote:before, blockquote:after, 42 | q:before, q:after { 43 | content: ""; 44 | } 45 | blockquote, q { 46 | quotes: "" ""; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/anneal.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.anneal) 10 | 11 | (defn exp [x] 12 | (js/Math.exp x)) 13 | 14 | (defn abs [x] 15 | (js/Math.abs x)) 16 | 17 | (defn random [] 18 | (js/Math.random)) 19 | 20 | (defn standard-prob [e e1 temp] 21 | (if (< e1 e) 22 | 1 23 | (exp (/ (- e e1) temp)))) 24 | 25 | (defn linear-cooling [steps] 26 | (let [min (- 1 (/ steps (dec steps)))] 27 | (fn [t] 28 | (max min (- 1 (/ t steps)))))) 29 | 30 | (defn anneal 31 | "Given an energy scoring function, a temperature function 32 | (calculates temp given iteration t), a permutation function (creates 33 | a candidate next state given a current state and iteration t), and 34 | an acceptance probability function (of last next energy and temp), 35 | yields a lazy seq of (accepted?) states of the form 36 | {:state s :score :best best :best-score :t t}" 37 | 38 | [energy ;;(energy state) -> score 39 | temp ;;(temp t) -> 0-1.0 40 | permute ;;(permute state t) -> new-state 41 | prob ;;(prob e e1 temp) -> 0-1.0 42 | state] 43 | 44 | (let [init state 45 | init-score (energy state) 46 | step (fn step [{:keys [state score best best-score t]:as ret}] 47 | (loop [next (permute state) t (inc t)] 48 | (let [next-score (energy next)] 49 | (if (> (prob score next-score (temp t)) (random)) 50 | (let [ret {:state next :score next-score :t t 51 | :best (if (< next-score best-score) next best) 52 | :best-score (min next-score best-score)}] 53 | (lazy-seq (cons ret (step ret)))) 54 | (recur (permute state) (inc t))))))] 55 | (step {:state init :score init-score :best init :best-score init-score :t 0}))) 56 | 57 | 58 | (comment 59 | 60 | (take 10 (take-nth 100 61 | (anneal #(abs (- % 42)) 62 | (linear-cooling 1000) 63 | (fn [s _] (+ s (- (random) 0.5))) 64 | standard-prob 65 | 55))) 66 | ) 67 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.dom-helpers 10 | (:require [clojure.string :as string] 11 | [goog.dom :as dom])) 12 | 13 | (defn get-element 14 | "Return the element with the passed id." 15 | [id] 16 | (dom/getElement (name id))) 17 | 18 | (defn append 19 | "Append all children to parent." 20 | [parent & children] 21 | (do (doseq [child children] 22 | (dom/appendChild parent child)) 23 | parent)) 24 | 25 | (defn set-text 26 | "Set the text content for the passed element returning the 27 | element. If a keyword is passed in the place of e, the element with 28 | that id will be used and returned." 29 | [e s] 30 | (let [e (if (keyword? e) (get-element e) e)] 31 | (doto e (dom/setTextContent s)))) 32 | 33 | (defn normalize-args [tag args] 34 | (let [parts (string/split (name tag) #"(\.|#)") 35 | [tag attrs] [(first parts) 36 | (apply hash-map (map #(cond (= % ".") :class 37 | (= % "#") :id 38 | :else %) 39 | (rest parts)))]] 40 | (if (map? (first args)) 41 | [tag (merge attrs (first args)) (rest args)] 42 | [tag attrs args]))) 43 | 44 | (defn element 45 | "Create a dom element using a keyword for the element name and a map 46 | for the attributes. Append all children to parent. If the first 47 | child is a string then the string will be set as the text content of 48 | the parent and all remaining children will be appended." 49 | [tag & args] 50 | (let [[tag attrs children] (normalize-args tag args) 51 | parent (dom/createDom (name tag) 52 | (reduce (fn [o [k v]] 53 | (aset o k v)) 54 | (js-obj) 55 | (map #(vector (name %1) %2) 56 | (keys attrs) 57 | (vals attrs)))) 58 | [parent children] (if (string? (first children)) 59 | [(set-text (element tag attrs) (first children)) 60 | (rest children)] 61 | [parent children])] 62 | (apply append parent children))) 63 | 64 | (defn remove-children 65 | "Remove all children from the element with the passed id." 66 | [id] 67 | (let [parent (dom/getElement (name id))] 68 | (do (dom/removeChildren parent)))) 69 | 70 | (defn html 71 | "Create a dom element from an html string." 72 | [s] 73 | (dom/htmlToDocumentFragment s)) 74 | 75 | (defn- element-arg? [x] 76 | (or (keyword? x) 77 | (map? x) 78 | (string? x))) 79 | 80 | (defn build 81 | "Build up a dom element from nested vectors." 82 | [x] 83 | (if (vector? x) 84 | (let [[parent children] (if (keyword? (first x)) 85 | [(apply element (take-while element-arg? x)) 86 | (drop-while element-arg? x)] 87 | [(first x) (rest x)]) 88 | children (map build children)] 89 | (apply append parent children)) 90 | x)) 91 | 92 | (defn insert-at 93 | "Insert a child element at a specific location." 94 | [parent child index] 95 | (dom/insertChildAt parent child index)) 96 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/layout.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.layout 10 | (:require [twitterbuzz.anneal :as ann] 11 | [twitterbuzz.radial :as rad] 12 | [goog.math :as math])) 13 | 14 | (defn random-loc [] 15 | {:x (ann/random) :y (ann/random)}) 16 | 17 | (defn sqr [x] 18 | (* x x)) 19 | 20 | (defn sqrt [x] 21 | (js/Math.sqrt x)) 22 | 23 | (defn dist [{x1 :x y1 :y} {x2 :x y2 :y}] 24 | (sqrt (+ (sqr (- x2 x1)) (sqr (- y2 y1))))) 25 | 26 | (defn init-state [mentions-data] 27 | (let [connected (reduce (fn [ret [k {:keys [mentions]}]] 28 | (if (pos? (count mentions)) 29 | (into (conj ret k) (keys mentions)) 30 | ret)) 31 | #{} mentions-data) 32 | mentions-data (select-keys mentions-data connected)] 33 | {:locs (zipmap connected (repeatedly #(random-loc))) 34 | :mentions mentions-data})) 35 | 36 | (defn roots [mentions-data] 37 | (let [parents (reduce (fn [ret [k {:keys [mentions]}]] 38 | (if (pos? (count mentions)) 39 | (conj ret k) 40 | ret)) 41 | #{} mentions-data)] 42 | (reduce disj parents (mapcat #(keys (:mentions %)) (vals mentions-data))))) 43 | 44 | (defn radial 45 | [mentions-data] 46 | (let [mentions #(rad/get-mentions mentions-data %) 47 | weights (rad/weights 48 | (into (set (roots mentions-data)) (mapcat mentions (keys mentions-data))) 49 | mentions)] 50 | {:mentions mentions-data 51 | :locs (-> (rad/layout (roots mentions-data) weights mentions) 52 | (rad/polar->cartesian 3))})) 53 | 54 | (defn score [{:keys [locs mentions]}] 55 | (let [metric (fn [d w] (sqr (- 1 (* d w)))) 56 | score-user (fn [[k {:keys [mentions]}]] 57 | (if (zero? (count mentions)) 58 | 0 59 | (let [loc (locs k)] 60 | (reduce (fn [score [ok w]] 61 | (+ score (metric (dist loc (locs ok)) w))) 62 | 0 63 | mentions))))] 64 | (reduce + (map score-user mentions)))) 65 | 66 | (defn permute-swap [{:keys [locs mentions]} t] 67 | ;;first cut - swap 68 | (let [xys (vec (vals locs)) 69 | swap1 (math/randomInt (count xys)) 70 | swap2 (math/randomInt (count xys)) 71 | temp (xys swap1) 72 | xys (assoc xys swap1 (xys swap2)) 73 | xys (assoc xys swap2 temp)] 74 | {:locs (zipmap (keys locs) xys) 75 | :mentions mentions})) 76 | 77 | (defn permute-move [{:keys [locs mentions]} t] 78 | (let [adj #(min 1.0 (max 0 (+ % (- (* (ann/random) 0.1) 0.05)))) 79 | move (fn [{:keys [x y] :as loc}] 80 | (if true ;;(> (ann/random) 0.8) 81 | {:x (adj x) 82 | :y (adj y)} 83 | loc)) 84 | xys (vec (vals locs))] 85 | {:locs (zipmap (keys locs) (map move (vals locs))) 86 | :mentions mentions})) 87 | 88 | (comment 89 | (def test-data {}) 90 | 91 | (def init (init-state test-data)) 92 | 93 | (map (fn [x] {:best-score (:best-score x) :t (:t x)}) 94 | (take 10 (take-nth 100 95 | (ann/anneal score 96 | (ann/linear-cooling 1000) 97 | permute-move 98 | ann/standard-prob 99 | init)))) 100 | ) 101 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.leaderboard 10 | (:require [twitterbuzz.core :as buzz] 11 | [twitterbuzz.dom-helpers :as dom])) 12 | 13 | (defn leaderboard-element 14 | "Create a leaderboard element from a user map." 15 | [user] 16 | (dom/build [:div.tweet 17 | [:img.profile-pic {:src (:image-url user)}] 18 | [:div.tweet-details 19 | [:div.user-name (:username user)] 20 | [:div.tweet-text (dom/html (buzz/markup (:last-tweet user)))] 21 | [:div (str (buzz/num-mentions user))]]])) 22 | 23 | (defn leaders 24 | "Given a map of users, return a sequence of users in order of the 25 | greatest to least number of mentions." 26 | [nodes] 27 | (reverse (sort-by #(buzz/num-mentions (second %)) nodes))) 28 | 29 | (defn update-leaderboard 30 | "Put the top 5 mentioned users in the leaderboard." 31 | [graph] 32 | (do (dom/remove-children :leaderboard-content) 33 | (doseq [next-node (take 5 (leaders (seq graph)))] 34 | (dom/append (dom/get-element :leaderboard-content) 35 | (leaderboard-element (second next-node)))))) 36 | 37 | ;; Register event listeners. 38 | 39 | (buzz/register :track-clicked #(dom/remove-children :leaderboard-content)) 40 | (buzz/register :graph-update update-leaderboard) 41 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/radial.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.radial 10 | (:require [clojure.set :as set] 11 | [goog.math :as math])) 12 | 13 | (defn get-mentions 14 | "Returns the set of mentions for k in mentions-data" 15 | [mentions-data k] 16 | (-> (get-in mentions-data [k :mentions]) 17 | keys 18 | set)) 19 | 20 | (defn get-descendants 21 | "Given child-fn (a map of parent to child), and k, return the 22 | set of all k's descendants. Set includes k." 23 | [child-fn k] 24 | (loop [kids #{k} 25 | check #{k}] 26 | (let [[c] (seq check)] 27 | (if c 28 | (recur (into kids (child-fn c)) 29 | (into (disj check c) (remove kids (child-fn c)))) 30 | kids)))) 31 | 32 | (defn weight 33 | "Weight of noce, given child-fn (mapping of node to set 34 | of kids)." 35 | [node child-fn] 36 | (if-let [kids (seq (child-fn node))] 37 | (reduce + (map #(weight % child-fn) kids)) 38 | 1)) 39 | 40 | (defn weights 41 | "Return a map of node to its weight, 42 | using child-fn to get the set of children for a node." 43 | [nodes child-fn] 44 | (reduce 45 | (fn [m n] (assoc m n (weight n child-fn))) 46 | {} 47 | nodes)) 48 | 49 | (defn layout 50 | "Returns a map of node => :radius, :slice, :angle. 51 | 52 | weight-fn: one arg fn of node returning weight 53 | child-fn: one arg fn of node returning set of nodes" 54 | ([nodes weight-fn child-fn] 55 | (layout nodes weight-fn child-fn 1 0 360 #{})) 56 | ([nodes weight-fn child-fn radius a1 a2 seen] 57 | (let [slice (- a2 a1) 58 | total-weight (reduce + (map #(or (weight-fn %) 59 | (throw (str "No weight for " %))) nodes)) 60 | seen (into seen nodes)] 61 | (loop [m {} 62 | c1 a1 63 | [node & more] (seq nodes)] 64 | (if node 65 | (let [s (* slice (/ (weight-fn node) total-weight)) 66 | c2 (+ c1 s)] 67 | (recur 68 | (merge 69 | m 70 | {node {:radius radius :slice s :angle (/ (+ c1 c2) 2)}} 71 | (when-let [children (seq (remove seen (child-fn node)))] 72 | (layout children weight-fn child-fn (inc radius) c1 c2 seen))) 73 | c2 74 | more)) 75 | m))))) 76 | 77 | (defn polar->cartesian 78 | "Convert polar coordinates (from layout) into 79 | cartesian coordinates on the unit square, assuming the 80 | square will display max-rings rings." 81 | [polar-map max-rings] 82 | (reduce 83 | (fn [m [k {:keys [radius angle]}]] 84 | (let [r (/ radius (+ 0.5 max-rings) 2)] 85 | (assoc m k {:x (+ 0.5 (math/angleDx angle r)) 86 | :y (+ 0.5 (math/angleDy angle r))}))) 87 | {} 88 | polar-map)) 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/showgraph.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.showgraph 10 | (:require [twitterbuzz.core :as buzz] 11 | [twitterbuzz.layout :as layout] 12 | [twitterbuzz.dom-helpers :as dom] 13 | [twitterbuzz.timeline :as timeline] 14 | [goog.events :as events] 15 | [goog.style :as style] 16 | [goog.math.Coordinate :as Coordinate] 17 | [goog.ui.HoverCard :as HoverCard] 18 | [goog.graphics.Font :as Font] 19 | [goog.graphics.Stroke :as Stroke] 20 | [goog.graphics.SolidFill :as SolidFill] 21 | [goog.graphics :as graphics])) 22 | 23 | ; Drawing configuration 24 | (def avatar-size 32) ; used for both x and y dimensions of avatars 25 | ; fail whale 26 | ;(def default-avatar "http://farm3.static.flickr.com/2562/4140195522_e207b97280_s.jpg") 27 | ; google+ silhouette 28 | (def default-avatar "http://ssl.gstatic.com/s2/profiles/images/silhouette48.png") 29 | (defn debug [_]) 30 | ;(defn debug [a] (str "t: " (:t a) " score: " (:best-score a))) 31 | 32 | ; BAD HACK: don't change globals like this -- find a better way: 33 | ;(set! anim/TIMEOUT 500) 34 | 35 | (def edge-stroke (graphics/Stroke. 1 "#009")) 36 | 37 | (def g 38 | (doto (graphics/createGraphics "100%" "100%") 39 | (.render (dom/get-element :network)))) 40 | 41 | (def font (graphics/Font. 12 "Arial")) 42 | (def fill (graphics/SolidFill. "#f00")) 43 | 44 | (defn unit-to-pixel [unit-arg canvas-size] 45 | (+ (* unit-arg (- canvas-size avatar-size)) (/ avatar-size 2))) 46 | 47 | (defn log [& args] 48 | (js/console.log (apply pr-str args))) 49 | 50 | (def avatar-hover 51 | (doto 52 | (goog.ui/HoverCard. (js-obj)) ; svg IMAGE tags don't work here 53 | (.setElement (dom/get-element :avatar-hover)))) 54 | 55 | (defn hide-tooltip [event] 56 | (.setVisible avatar-hover false)) 57 | 58 | (defn attach-tooltip [img canvas-offset px py tweet] 59 | (events/listen img events/EventType.MOUSEOUT hide-tooltip) 60 | (events/listen 61 | img events/EventType.MOUSEOVER 62 | (fn [event] 63 | (hide-tooltip event) 64 | (.setPosition avatar-hover 65 | (goog.ui/Tooltip.CursorTooltipPosition. 66 | (Coordinate/sum (goog.math/Coordinate. px py) 67 | canvas-offset))) 68 | (dom/remove-children :avatar-hover-body) 69 | (dom/append (dom/get-element :avatar-hover-body) 70 | (timeline/timeline-element tweet)) 71 | (.triggerForElement avatar-hover img)))) 72 | 73 | (defn draw-graph [{:keys [locs mentions]} text] 74 | (let [canvas-size (. g (getPixelSize)) 75 | canvas-offset (style/getPageOffset (dom/get-element :network))] 76 | (. g (clear)) 77 | 78 | ; Draw mention edges 79 | (doseq [[username {ux1 :x, uy1 :y}] locs 80 | :let [x1 (unit-to-pixel ux1 (.-width canvas-size)) 81 | y1 (unit-to-pixel uy1 (.-height canvas-size))] 82 | [mention-name mention-count] (:mentions (get mentions username))] 83 | (when-let [{ux2 :x, uy2 :y} (get locs mention-name)] 84 | (let [x2 (unit-to-pixel ux2 (.-width canvas-size)) 85 | y2 (unit-to-pixel uy2 (.-height canvas-size))] 86 | (.drawPath g 87 | (-> (. g (createPath)) (.moveTo x1 y1) (.lineTo x2 y2)) 88 | edge-stroke nil)))) 89 | 90 | ; Draw avatar nodes 91 | (doseq [[username {:keys [x y] :as foo}] locs] 92 | ;(log (pr-str foo)) 93 | (let [px (- (unit-to-pixel x (.-width canvas-size)) (/ avatar-size 2)) 94 | py (- (unit-to-pixel y (.-height canvas-size)) (/ avatar-size 2)) 95 | user (get mentions username) 96 | image-url (get user :image-url default-avatar) 97 | img (.drawImage g px py avatar-size avatar-size image-url)] 98 | (attach-tooltip img canvas-offset px py 99 | {:profile_image_url image-url 100 | :text (:last-tweet user) 101 | :from_user (:username user)}))) 102 | 103 | (let [text (if (empty? locs) 104 | "No locations to graph" 105 | text)] 106 | (when text 107 | (.drawTextOnLine g text 5 20 (.-width canvas-size) 20 108 | "left" font nil fill))))) 109 | 110 | (def graph-data (atom nil)) 111 | 112 | ;; Register event listeners. 113 | 114 | (buzz/register :graph-update 115 | (fn [data] 116 | (reset! graph-data data) 117 | (draw-graph (layout/radial data) nil))) 118 | 119 | (events/listen (dom/get-element :network) events/EventType.CLICK 120 | #(draw-graph (layout/radial @graph-data) nil)) 121 | (buzz/register :track-clicked #(. g (clear))) 122 | -------------------------------------------------------------------------------- /samples/twitterbuzz/src/twitterbuzz/timeline.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns twitterbuzz.timeline 10 | (:require [twitterbuzz.core :as buzz] 11 | [twitterbuzz.dom-helpers :as dom])) 12 | 13 | (defn timeline-element 14 | "Return a timeline dom element for the given tweet." 15 | [tweet] 16 | (dom/build [:div.tweet 17 | [:img.profile-pic {:src (:profile_image_url tweet)}] 18 | [:div.user-name (:from_user tweet)] 19 | [:div.tweet-text (dom/html (buzz/markup (:text tweet)))]])) 20 | 21 | (defn update-status 22 | "Set the current tweet count in the status box." 23 | [_] 24 | (buzz/set-tweet-status :okay (str (:tweet-count @buzz/state) " tweets"))) 25 | 26 | (defn update-timeline 27 | "Given a list of tweets in chronological order, add them to the top 28 | of the list view." 29 | [tweets] 30 | (doseq [tweet (reverse tweets)] 31 | (dom/insert-at (dom/get-element :timeline-content) 32 | (timeline-element tweet) 33 | 0))) 34 | 35 | ;; Register event listeners. 36 | 37 | (buzz/register :track-clicked #(dom/remove-children :timeline-content)) 38 | (buzz/register :new-tweets update-timeline) 39 | (buzz/register :new-tweets update-status) 40 | -------------------------------------------------------------------------------- /script/benchmark: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf builds/out-adv-bench 4 | mkdir -p builds/out-adv-bench 5 | 6 | bin/cljsc benchmark "{:optimizations :advanced :output-wrapper true :compiler-stats true}" > builds/out-adv-bench/core-advanced-benchmark.js 7 | 8 | if [ "$V8_HOME" = "" ]; then 9 | echo "V8_HOME not set, skipping V8 benchmarks" 10 | else 11 | echo "Benchmarking with V8" 12 | "${V8_HOME}/d8" builds/out-adv-bench/core-advanced-benchmark.js 13 | fi 14 | 15 | if [ "$SPIDERMONKEY_HOME" = "" ]; then 16 | echo "SPIDERMONKEY_HOME not set, skipping SpiderMonkey benchmarks" 17 | else 18 | echo "Benchmarking with SpiderMonkey" 19 | "${SPIDERMONKEY_HOME}/js" -f builds/out-adv-bench/core-advanced-benchmark.js 20 | fi 21 | 22 | if [ "$JSC_HOME" = "" ]; then 23 | echo "JSC_HOME not set, skipping JavaScriptCore benchmarks" 24 | else 25 | echo "Benchmarking with JavaScriptCore" 26 | "${JSC_HOME}/jsc" -f builds/out-adv-bench/core-advanced-benchmark.js 27 | fi 28 | 29 | if [ "$NASHORN_HOME" = "" ]; then 30 | echo "NASHORN_HOME not set, skipping Nashorn benchmarks" 31 | else 32 | echo "Benchmarking with Nashorn" 33 | "${NASHORN_HOME}/jjs" builds/out-adv-bench/core-advanced-benchmark.js 34 | fi 35 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | CLOJURE_RELEASE="1.6.0" 6 | CLOSURE_RELEASE="20140625" 7 | DJSON_RELEASE="0.2.3" 8 | GCLOSURE_LIB_RELEASE="0.0-20140718-946a7d39" 9 | RHINO_RELEASE="1_7R3" 10 | TREADER_RELEASE="0.8.10" 11 | 12 | # check dependencies 13 | curl -V >/dev/null || { echo "cURL is missing, or not on your system path."; exit 1; } 14 | unzip -v >/dev/null || { echo "The 'unzip' utility is missing, or not on your system path."; exit 1; } 15 | 16 | mkdir -p lib 17 | 18 | echo "Fetching Clojure..." 19 | curl -O -s https://repo1.maven.org/maven2/org/clojure/clojure/$CLOJURE_RELEASE/clojure-$CLOJURE_RELEASE.zip || { echo "Download failed."; exit 1; } 20 | unzip -qu clojure-$CLOJURE_RELEASE.zip 21 | echo "Copying clojure-$CLOJURE_RELEASE/clojure-$CLOJURE_RELEASE.jar to lib/clojure.jar..." 22 | cp clojure-$CLOJURE_RELEASE/clojure-$CLOJURE_RELEASE.jar lib/clojure.jar 23 | 24 | echo "Cleaning up Clojure directory..." 25 | rm -rf clojure-$CLOJURE_RELEASE/ 26 | echo "Cleaning up Clojure archive..." 27 | rm clojure-$CLOJURE_RELEASE.zip 28 | 29 | echo "Fetching data.json..." 30 | curl --retry 3 -O -s https://repo1.maven.org/maven2/org/clojure/data.json/$DJSON_RELEASE/data.json-$DJSON_RELEASE.jar || { echo "Download failed."; exit 1; } 31 | echo "Copying data.json-$DJSON_RELEASE.jar to lib/data.json-$DJSON_RELEASE.jar..." 32 | cp data.json-$DJSON_RELEASE.jar lib/data.json-$DJSON_RELEASE.jar 33 | echo "Cleaning up data.json..." 34 | rm data.json-$DJSON_RELEASE.jar 35 | 36 | echo "Fetching Google Closure library..." 37 | mkdir -p closure/library 38 | cd closure/library 39 | if [ "$1" = "--closure-library-head" ] ; then 40 | echo "Building against HEAD of Google Closure library..." 41 | 42 | # Check if svn present 43 | type svn >/dev/null 2>&1 || { echo >&2 "Need svn command to checkout HEAD of Google Closure library. Aborting."; exit 1; } 44 | 45 | # Existing checkout? 46 | if svn info --non-interactive >/dev/null 2>&1; then 47 | echo "Updating Google Closure library from HEAD..." 48 | svn update -q --non-interactive 49 | else 50 | echo "Checking out HEAD of Google Closure library..." 51 | rm -rf * 52 | svn checkout -q --non-interactive https://closure-library.googlecode.com/svn/trunk/ ./ 53 | fi 54 | else 55 | curl --retry 3 -O -s https://repo1.maven.org/maven2/org/clojure/google-closure-library/$GCLOSURE_LIB_RELEASE/google-closure-library-$GCLOSURE_LIB_RELEASE.jar || { echo "Download failed."; exit 1; } 56 | cp google-closure-library-$GCLOSURE_LIB_RELEASE.jar ../../lib/google-closure-library-$GCLOSURE_LIB_RELEASE.jar 57 | rm google-closure-library-$GCLOSURE_LIB_RELEASE.jar 58 | 59 | echo "Fetching Google Closure third party library..." 60 | curl --retry 3 -O -s https://repo1.maven.org/maven2/org/clojure/google-closure-library-third-party/$GCLOSURE_LIB_RELEASE/google-closure-library-third-party-$GCLOSURE_LIB_RELEASE.jar || { echo "Download failed."; exit 1; } 61 | cp google-closure-library-third-party-$GCLOSURE_LIB_RELEASE.jar ../../lib/google-closure-library-third-party-$GCLOSURE_LIB_RELEASE.jar 62 | rm google-closure-library-third-party-$GCLOSURE_LIB_RELEASE.jar 63 | fi 64 | cd .. 65 | 66 | echo "Fetching Google Closure compiler..." 67 | mkdir -p compiler 68 | cd compiler 69 | curl --retry 3 -O -s http://dl.google.com/closure-compiler/compiler-$CLOSURE_RELEASE.zip || { echo "Download failed."; exit 1; } 70 | unzip -qu compiler-$CLOSURE_RELEASE.zip 71 | echo "Cleaning up Google Closure compiler archive..." 72 | rm compiler-$CLOSURE_RELEASE.zip 73 | cd ../.. 74 | 75 | if [ "$1" = "--closure-library-head" ] ; then 76 | echo "Building lib/goog.jar..." 77 | echo "jar cf ./lib/goog.jar -C closure/library/closure/ goog" 78 | jar cf ./lib/goog.jar -C closure/library/closure/ goog 79 | fi 80 | 81 | echo "Fetching Rhino..." 82 | curl --retry 3 -O -s https://ftp.mozilla.org/pub/mozilla.org/js/rhino$RHINO_RELEASE.zip || { echo "Download failed."; exit 1; } 83 | unzip -qu rhino$RHINO_RELEASE.zip 84 | echo "Copying rhino$RHINO_RELEASE/js.jar to lib/js.jar..." 85 | cp rhino$RHINO_RELEASE/js.jar lib/js.jar 86 | echo "Cleaning up Rhino directory..." 87 | rm -rf rhino$RHINO_RELEASE/ 88 | echo "Cleaning up Rhino archive..." 89 | rm rhino$RHINO_RELEASE.zip 90 | 91 | echo "Copying closure/compiler/compiler.jar to lib/compiler.jar" 92 | cp closure/compiler/compiler.jar lib 93 | 94 | echo "Fetching tools.reader $TREADER_RELEASE ..." 95 | curl --retry 3 -O -s https://repo1.maven.org/maven2/org/clojure/tools.reader/$TREADER_RELEASE/tools.reader-$TREADER_RELEASE.jar || { echo "Download failed."; exit 1; } 96 | 97 | echo "Moving tools.reader.jar to lib/tools.reader.jar" 98 | mv tools.reader-$TREADER_RELEASE.jar lib/tools.reader-$TREADER_RELEASE.jar 99 | 100 | echo "[Bootstrap Completed]" 101 | -------------------------------------------------------------------------------- /script/browser-repl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$CLOJURESCRIPT_HOME" = "" ]; then 4 | CLOJURESCRIPT_HOME="`dirname $0`/.." 5 | fi 6 | 7 | CLJSC_CP='' 8 | for next in lib/*: src/clj: src/cljs: test/cljs; do 9 | CLJSC_CP=$CLJSC_CP$CLOJURESCRIPT_HOME'/'$next 10 | done 11 | 12 | java -server -cp $CLJSC_CP clojure.main -e " 13 | (require '[cljs.repl :as r]) 14 | (require '[cljs.repl.browser :as b]) 15 | (r/repl (b/repl-env)) 16 | " 17 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script must be run within the ClojureScript top-level project 4 | # directory. 5 | 6 | set -ex 7 | 8 | cd `dirname $0`/.. 9 | 10 | POM_TEMPLATE="pom.template.xml" 11 | POM_FILE="pom.xml" 12 | 13 | # The command `git describe --match v0.0` will return a string like 14 | # 15 | # v0.0-856-g329708b 16 | # 17 | # where 856 is the number of commits since the v0.0 tag. It will always 18 | # find the v0.0 tag and will always return the total number of commits (even 19 | # if the tag is v0.0.1). 20 | REVISION=`git --no-replace-objects describe --match v0.0` 21 | 22 | # Extract the version number from the string. Do this in two steps so 23 | # it is a little easier to understand. 24 | REVISION=${REVISION:5} # drop the first 5 characters 25 | REVISION=${REVISION:0:${#REVISION}-9} # drop the last 9 characters 26 | 27 | TAG=r$REVISION 28 | 29 | sed -e s/CLOJURESCRIPT_VERSION/0.0-$REVISION/ < "$POM_TEMPLATE" > "$POM_FILE" 30 | 31 | COMP_FILE=`mktemp /tmp/compiler.clj.XXXXXXXXXXX` 32 | sed -e 's/^.def ^:dynamic \*clojurescript-version\*.*$/(def ^:dynamic *clojurescript-version* {:major 0, :minor 0, :qualifier '"$REVISION"'})/' src/clj/cljs/util.clj > $COMP_FILE 33 | mv $COMP_FILE src/clj/cljs/util.clj 34 | 35 | CLJS_FILE=`mktemp /tmp/core.cljs.XXXXXXXXXXX` 36 | sed -e 's/^.def \*clojurescript-version\*.*$/(def *clojurescript-version* '\""0.0-$REVISION"\"')/' src/cljs/cljs/core.cljs > $CLJS_FILE 37 | mv $CLJS_FILE src/cljs/cljs/core.cljs 38 | 39 | # For Hudson server 40 | if [ "$HUDSON" = "true" ]; then 41 | mvn --fail-at-end -Psonatype-oss-release \ 42 | clean deploy nexus-staging:release 43 | 44 | echo "Creating tag $TAG" 45 | git tag -f "$TAG" 46 | git push origin "$TAG" 47 | else 48 | echo "Skipping remote deployment and Git tag because we are not on Hudson." 49 | mvn clean install 50 | fi 51 | -------------------------------------------------------------------------------- /script/clean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf closure 4 | rm -rf compilation 5 | rm -rf lib 6 | -------------------------------------------------------------------------------- /script/closure-library-release/.gitignore: -------------------------------------------------------------------------------- 1 | closure-library/ 2 | tmp-build/ 3 | -------------------------------------------------------------------------------- /script/closure-library-release/closure-library-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # closure-library-release.sh 4 | 5 | # ClojureScript depends on the Google Closure JavaScript Libraries, 6 | # but Google does not publish those libraries in a Maven repository. 7 | # This script builds generates Maven projects for the Google Closure 8 | # Library and, optionally, deploys them. 9 | 10 | # The Google Closure Libraries are divided into two parts: the main 11 | # library and third-party extensions. The main library is Apache 12 | # licensed; the third-party extensions have a variety of different 13 | # licenses. However, code in the main library depends on the 14 | # third-party extensions, not the other way around. See CLJS-418 for 15 | # details. 16 | 17 | # To manage this, we build two JARs, google-closure-library and 18 | # google-closure-library-third-party, with the former declaring an 19 | # explicit dependency on the latter. This permits consumers to exclude 20 | # the third-party libraries (and their various licenses) if they know 21 | # they don't need them. 22 | 23 | # To match this structure, we need to alter the deps.js file that the 24 | # Google Closure Compiler uses to resolve dependencies. See CLJS-276 25 | # for details. 26 | 27 | # The last release ZIP made by Google was 20130212-95c19e7f0f5f. To 28 | # get newer versions, we have to go to the Git repository. 29 | 30 | 31 | set -e 32 | 33 | ### Constants 34 | 35 | POM_TEMPLATE_FILE="google-closure-library.pom.template" 36 | THIRD_PARTY_POM_TEMPLATE_FILE="google-closure-library-third-party.pom.template" 37 | GIT_CLONE_URL="git@github.com:google/closure-library.git" 38 | 39 | ### Functions 40 | 41 | function print_usage { 42 | echo "Usage: ./make-closure-library-jars.sh 43 | 44 | is the root directory of the Google Closure library 45 | Git repository." 46 | } 47 | 48 | ### MAIN SCRIPT BEGINS HERE 49 | 50 | ## Command-line validation 51 | 52 | if [[ ! -e $POM_TEMPLATE_FILE || ! -e $THIRD_PARTY_POM_TEMPLATE_FILE ]]; then 53 | echo "This script must be run from the directory containing 54 | google-closure-library.pom.template and 55 | google-closure-library-third-party.pom.template" 56 | exit 1 57 | fi 58 | 59 | ## Fetch the Git repo 60 | 61 | closure_library_dir="closure-library" 62 | 63 | if [[ ! -d $closure_library_dir ]]; then 64 | git clone "$GIT_CLONE_URL" "$closure_library_dir" 65 | fi 66 | 67 | ( 68 | cd "$closure_library_dir" 69 | git clean -fdx 70 | git checkout master 71 | git pull 72 | ) 73 | 74 | closure_library_base="$closure_library_dir/closure" 75 | third_party_base="$closure_library_dir/third_party/closure" 76 | 77 | if [[ ! -d $closure_library_base || ! -d $third_party_base ]]; then 78 | echo "$closure_library_dir does not look like the Closure library" 79 | exit 1 80 | fi 81 | 82 | ## Working directory 83 | 84 | now=$(date "+%Y%m%d%H%M%S") 85 | work_dir="tmp-build" 86 | 87 | echo "Working directory: $work_dir" 88 | 89 | rm -rf "$work_dir" 90 | mkdir "$work_dir" 91 | 92 | ## Git parsing for release version 93 | 94 | commit_details=$(cd "$closure_library_dir"; git log -n 1 '--pretty=format:%H %ci') 95 | 96 | commit_short_sha=${commit_details:0:8} 97 | commit_date="${commit_details:41:4}${commit_details:46:2}${commit_details:49:2}" 98 | release_version="0.0-${commit_date}-${commit_short_sha}" 99 | 100 | echo "HEAD commit: $commit_details" 101 | echo "Date: $commit_date" 102 | echo "Short SHA: $commit_short_sha" 103 | echo "Release version: $release_version" 104 | 105 | ## Creating directories 106 | 107 | project_dir="$work_dir/google-closure-library" 108 | src_dir="$project_dir/src/main/resources" 109 | 110 | third_party_project_dir="$work_dir/google-closure-library-third-party" 111 | third_party_src_dir="$third_party_project_dir/src/main/resources" 112 | 113 | mkdir -p "$src_dir" "$third_party_src_dir" 114 | 115 | ## Copy Closure sources 116 | 117 | cp -r \ 118 | "$closure_library_dir/AUTHORS" \ 119 | "$closure_library_dir/LICENSE" \ 120 | "$closure_library_dir/README" \ 121 | "$closure_library_dir/closure/goog" \ 122 | "$closure_library_dir/closure/css" \ 123 | "$src_dir" 124 | 125 | cp -r \ 126 | "$closure_library_dir/AUTHORS" \ 127 | "$closure_library_dir/LICENSE" \ 128 | "$closure_library_dir/README" \ 129 | "$closure_library_dir/third_party/closure/goog" \ 130 | "$third_party_src_dir" 131 | 132 | ## Modify main deps.js for third-party JAR; see CLJS-276: 133 | 134 | perl -p -i -e 's/..\/..\/third_party\/closure\/goog\///go' \ 135 | "$src_dir/goog/deps.js" 136 | 137 | ## Remove empty third-party deps.js and base.js 138 | 139 | rm -f \ 140 | "$third_party_src_dir/goog/deps.js" \ 141 | "$third_party_src_dir/goog/base.js" 142 | 143 | ## Generate the POM files: 144 | 145 | perl -p -e "s/RELEASE_VERSION/$release_version/go" \ 146 | "$POM_TEMPLATE_FILE" \ 147 | > "$project_dir/pom.xml" 148 | 149 | perl -p -e "s/RELEASE_VERSION/$release_version/go" \ 150 | "$THIRD_PARTY_POM_TEMPLATE_FILE" \ 151 | > "$third_party_project_dir/pom.xml" 152 | 153 | ## Deploy the files if we are on Hudson 154 | 155 | if [ "$HUDSON" = "true" ]; then 156 | ( 157 | cd "$third_party_project_dir" 158 | mvn --fail-at-end \ 159 | -Psonatype-oss-release \ 160 | -Dsource.skip=true \ 161 | clean deploy 162 | ) 163 | 164 | ( 165 | cd "$project_dir" 166 | mvn --fail-at-end \ 167 | -Psonatype-oss-release \ 168 | -Dsource.skip=true \ 169 | clean deploy 170 | ) 171 | 172 | echo "Now log in to https://oss.sonatype.org/ to release" 173 | echo "the staging repository." 174 | else 175 | echo "Skipping deployment because we are not on Hudson." 176 | fi 177 | -------------------------------------------------------------------------------- /script/closure-library-release/google-closure-library-third-party.pom.template: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | org.clojure 4 | google-closure-library-third-party 5 | RELEASE_VERSION 6 | jar 7 | Google Closure Library Third-Party Extensions 8 | 9 | 10 | org.sonatype.oss 11 | oss-parent 12 | 9 13 | 14 | 15 | http://code.google.com/p/closure-library/ 16 | 17 | 18 | The Google Closure Library is a collection of JavaScript code 19 | designed for use with the Google Closure JavaScript Compiler. 20 | 21 | This non-official distribution was prepared by the ClojureScript 22 | team at http://clojure.org/ 23 | 24 | This package contains extensions to the Google Closure Library 25 | using third-party components, which may be distributed under 26 | licenses other than the Apache license. Licenses for individual 27 | library components may be found in source-code comments. 28 | 29 | 30 | 31 | 32 | The Apache Software License, Version 2.0 33 | http://www.apache.org/licenses/LICENSE-2.0.html 34 | repo 35 | 36 | Note: the Google Closure library third-party extensions 37 | contain code under a variety of licenses, which may be found 38 | in source-code comments in each file. 39 | 40 | 41 | 42 | 43 | 44 | Google 45 | http://www.google.com 46 | 47 | 48 | 49 | Google, Inc. 50 | Mohamed Mansourhello@mohamedmansour.com 51 | Bjorn Tiplingbjorn.tipling@gmail.com 52 | SameGoal LLChelp@samegoal.com 53 | Guido Tapiaguido.tapia@gmail.com 54 | Andrew Mattieamattie@gmail.com 55 | Ilia Mirkinibmirkin@gmail.com 56 | Ivan Kozikivan.kozik@gmail.com 57 | Rich Doughertyrich@rd.gen.nz 58 | 59 | 60 | 61 | scm:https://github.com/google/closure-library.git 62 | scm:git:https://github.com/google/closure-library.git 63 | https://github.com/google/closure-library 64 | 65 | 66 | 67 | code.google.com 68 | http://code.google.com/p/closure-library/issues 69 | 70 | 71 | 72 | 73 | sonatype-oss-release 74 | 76 | 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-deploy-plugin 81 | 2.7 82 | 83 | true 84 | 85 | 86 | 87 | org.sonatype.plugins 88 | nexus-staging-maven-plugin 89 | 1.4.4 90 | 91 | 92 | default-deploy 93 | deploy 94 | 95 | 96 | deploy 97 | 98 | 99 | 100 | 101 | 102 | https://oss.sonatype.org/ 103 | 104 | sonatype-nexus-staging 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /script/closure-library-release/google-closure-library.pom.template: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | org.clojure 4 | google-closure-library 5 | RELEASE_VERSION 6 | jar 7 | Google Closure Library 8 | 9 | 10 | org.sonatype.oss 11 | oss-parent 12 | 9 13 | 14 | 15 | http://code.google.com/p/closure-library/ 16 | 17 | 18 | The Google Closure Library is a collection of JavaScript code 19 | designed for use with the Google Closure JavaScript Compiler. 20 | 21 | This non-official distribution was prepared by the ClojureScript 22 | team at http://clojure.org/ 23 | 24 | 25 | 26 | 27 | org.clojure 28 | google-closure-library-third-party 29 | RELEASE_VERSION 30 | 31 | 32 | 33 | 34 | 35 | The Apache Software License, Version 2.0 36 | http://www.apache.org/licenses/LICENSE-2.0.html 37 | repo 38 | 39 | 40 | 41 | 42 | Google 43 | http://www.google.com 44 | 45 | 46 | 47 | Google, Inc. 48 | Mohamed Mansourhello@mohamedmansour.com 49 | Bjorn Tiplingbjorn.tipling@gmail.com 50 | SameGoal LLChelp@samegoal.com 51 | Guido Tapiaguido.tapia@gmail.com 52 | Andrew Mattieamattie@gmail.com 53 | Ilia Mirkinibmirkin@gmail.com 54 | Ivan Kozikivan.kozik@gmail.com 55 | Rich Doughertyrich@rd.gen.nz 56 | 57 | 58 | 59 | scm:https://github.com/google/closure-library.git 60 | scm:git:https://github.com/google/closure-library.git 61 | https://github.com/google/closure-library 62 | 63 | 64 | 65 | code.google.com 66 | http://code.google.com/p/closure-library/issues 67 | 68 | 69 | 70 | 71 | sonatype-oss-release 72 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-deploy-plugin 79 | 2.7 80 | 81 | true 82 | 83 | 84 | 85 | org.sonatype.plugins 86 | nexus-staging-maven-plugin 87 | 1.4.4 88 | 89 | 90 | default-deploy 91 | deploy 92 | 93 | 94 | deploy 95 | 96 | 97 | 98 | 99 | 100 | https://oss.sonatype.org/ 101 | 102 | sonatype-nexus-staging 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /script/compile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f core.js 4 | 5 | java -server -Xmx2G -Xms2G -Xmn256m -cp 'lib/*:src/clj:src/cljs' clojure.main - < coresimple.js 25 | 26 | java -jar closure/compiler/compiler.jar \ 27 | --compilation_level=ADVANCED_OPTIMIZATIONS \ 28 | --warning_level=VERBOSE \ 29 | --formatting=PRETTY_PRINT \ 30 | --jscomp_off=missingProperties \ 31 | --js closure/library/closure/goog/base.js \ 32 | --js closure/library/closure/goog/string/string.js \ 33 | --js closure/library/closure/goog/useragent/jscript.js \ 34 | --js closure/library/closure/goog/string/stringbuffer.js \ 35 | --js closure/library/closure/goog/object/object.js \ 36 | --js closure/library/closure/goog/debug/error.js \ 37 | --js closure/library/closure/goog/asserts/asserts.js \ 38 | --js closure/library/closure/goog/array/array.js \ 39 | --js core.js \ 40 | > coreadvanced.js 41 | 42 | -------------------------------------------------------------------------------- /script/noderepljs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$CLOJURESCRIPT_HOME" = "" ]; then 4 | CLOJURESCRIPT_HOME="`dirname $0`/.." 5 | fi 6 | 7 | CLJSC_CP='' 8 | for next in lib/*: src/clj: src/cljs: test/cljs; do 9 | CLJSC_CP=$CLJSC_CP$CLOJURESCRIPT_HOME'/'$next 10 | done 11 | 12 | java -server -cp $CLJSC_CP clojure.main -e \ 13 | "(require '[cljs.repl :as repl]) 14 | (require '[cljs.repl.node :as node]) 15 | (repl/repl* (node/repl-env $1) {:output-dir \".cljs_node_repl\" :cache-analysis true :source-map true})" 16 | -------------------------------------------------------------------------------- /script/repl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$CLOJURESCRIPT_HOME" = "" ]; then 4 | CLOJURESCRIPT_HOME="`dirname $0`/.." 5 | fi 6 | 7 | CLJSC_CP='' 8 | for next in classes: lib/*: src/clj: src/cljs: test/cljs; do 9 | CLJSC_CP="${CLJSC_CP}${CLOJURESCRIPT_HOME}/${next}" 10 | done 11 | 12 | java -server -cp "$CLJSC_CP" clojure.main "$@" 13 | 14 | -------------------------------------------------------------------------------- /script/repl.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setLocal EnableDelayedExpansion 3 | 4 | if "%CLOJURESCRIPT_HOME%" == "" set CLOJURESCRIPT_HOME=%~dp0..\ 5 | 6 | set CLASSPATH=%CLOJURESCRIPT_HOME%src\clj;%CLOJURESCRIPT_HOME%src\cljs" 7 | for /R "%CLOJURESCRIPT_HOME%\lib" %%a in (*.jar) do ( 8 | set CLASSPATH=!CLASSPATH!;%%a 9 | ) 10 | set CLASSPATH=!CLASSPATH!" 11 | 12 | java -server -cp "%CLASSPATH%" clojure.main 13 | 14 | -------------------------------------------------------------------------------- /script/repljs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$CLOJURESCRIPT_HOME" = "" ]; then 4 | CLOJURESCRIPT_HOME="`dirname $0`/.." 5 | fi 6 | 7 | CLJSC_CP='' 8 | for next in classes: lib/*: src/clj: src/cljs: test/cljs; do 9 | CLJSC_CP="${CLJSC_CP}${CLOJURESCRIPT_HOME}/${next}" 10 | done 11 | 12 | java -server -cp "$CLJSC_CP" clojure.main -e \ 13 | "(require '[cljs.repl :as repl]) 14 | (require '[cljs.repl.rhino :as rhino]) 15 | (repl/repl* (rhino/repl-env) {:warn-on-undeclared true :output-dir \".cljs_repl\" :cache-analysis true})" 16 | -------------------------------------------------------------------------------- /script/repljs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setLocal EnableDelayedExpansion 3 | 4 | if "%CLOJURESCRIPT_HOME%" == "" set CLOJURESCRIPT_HOME=%~dp0..\ 5 | 6 | set CLASSPATH=%CLOJURESCRIPT_HOME%src\clj;%CLOJURESCRIPT_HOME%src\cljs" 7 | for /R "%CLOJURESCRIPT_HOME%\lib" %%a in (*.jar) do ( 8 | set CLASSPATH=!CLASSPATH!;%%a 9 | ) 10 | set CLASSPATH=!CLASSPATH!" 11 | 12 | set REPL_CLJ="(require '[cljs.repl :as repl])(require '[cljs.repl.rhino :as rhino])(repl/repl (rhino/repl-env))" 13 | 14 | java -server -cp "%CLASSPATH%" clojure.main -e %REPL_CLJ% 15 | -------------------------------------------------------------------------------- /script/self-compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf classes 4 | mkdir classes 5 | ./script/repl -e "(compile 'cljs.repl.node) (compile 'cljs.repl.browser) (compile 'cljs.repl.rhino) (compile 'cljs.core)" 6 | -------------------------------------------------------------------------------- /script/test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf builds/out-adv 4 | mkdir -p builds/out-adv 5 | 6 | possible=4 7 | ran=0 8 | 9 | #bin/cljsc test >out/core-test.js 10 | bin/cljsc test "{:optimizations :advanced :output-wrapper true :compiler-stats true}" > builds/out-adv/core-advanced-test.js 11 | 12 | if [ "$V8_HOME" = "" ]; then 13 | echo "V8_HOME not set, skipping V8 tests" 14 | else 15 | echo "Testing with V8" 16 | "${V8_HOME}/d8" builds/out-adv/core-advanced-test.js 17 | ran=$((ran+1)) 18 | fi 19 | 20 | if [ "$SPIDERMONKEY_HOME" = "" ]; then 21 | echo "SPIDERMONKEY_HOME not set, skipping SpiderMonkey tests" 22 | else 23 | echo "Testing with SpiderMonkey" 24 | ${SPIDERMONKEY_HOME}/js -f builds/out-adv/core-advanced-test.js 25 | ran=$((ran+1)) 26 | fi 27 | 28 | if [ "$JSC_HOME" = "" ]; then 29 | echo "JSC_HOME not set, skipping JavaScriptCore tests" 30 | else 31 | echo "Testing with JavaScriptCore" 32 | "${JSC_HOME}/jsc" -f builds/out-adv/core-advanced-test.js 33 | ran=$((ran+1)) 34 | fi 35 | 36 | if [ "$NASHORN_HOME" = "" ]; then 37 | echo "NASHORN_HOME not set, skipping Nashorn tests" 38 | else 39 | echo "Testing with Nashorn" 40 | "${NASHORN_HOME}/jjs" builds/out-adv/core-advanced-test.js 41 | ran=$((ran+1)) 42 | fi 43 | 44 | echo "Tested with $ran out of $possible possible js targets" 45 | -------------------------------------------------------------------------------- /script/test-compile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Generating sample javascript" 4 | mkdir compilation 5 | 6 | cat >compilation/test.js <out/core-test.js 11 | bin/cljsc test "{:optimizations :simple :static-fns true :output-dir \"builds/out-simp\" :cache-analysis true :output-wrapper true :compiler-stats true}" > builds/out-simp/core-simple-test.js 12 | 13 | if [ "$V8_HOME" = "" ]; then 14 | echo "V8_HOME not set, skipping V8 tests" 15 | else 16 | echo "Testing with V8" 17 | "${V8_HOME}/d8" builds/out-simp/core-simple-test.js 18 | ran=$[ran+1] 19 | fi 20 | 21 | if [ "$SPIDERMONKEY_HOME" = "" ]; then 22 | echo "SPIDERMONKEY_HOME not set, skipping SpiderMonkey tests" 23 | else 24 | echo "Testing with SpiderMonkey" 25 | ${SPIDERMONKEY_HOME}/js -f builds/out-simp/core-simple-test.js 26 | ran=$[ran+1] 27 | fi 28 | 29 | # commented out because of memory issue in JSC w/ nested fn calls - David 30 | #if [ "$JSC_HOME" = "" ]; then 31 | # echo "JSC_HOME not set, skipping JavaScriptCore tests" 32 | #else 33 | # echo "Testing with JavaScriptCore" 34 | # "${JSC_HOME}/jsc" -f builds/out-simp/core-simple-test.js 35 | # ran=$[ran+1] 36 | #fi 37 | 38 | if [ "$NASHORN_HOME" = "" ]; then 39 | echo "NASHORN_HOME not set, skipping Nashorn tests" 40 | else 41 | echo "Testing with Nashorn" 42 | "${NASHORN_HOME}/jjs" builds/out-simp/core-simple-test.js 43 | ran=$[ran+1] 44 | fi 45 | 46 | echo "Tested with $ran out of $possible possible js targets" 47 | -------------------------------------------------------------------------------- /src/clj/cljs/analyzer/api.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.analyzer.api 10 | (:refer-clojure :exclude [all-ns ns-interns ns-resolve resolve find-ns]) 11 | (:require [cljs.env :as env] 12 | [cljs.analyzer :as ana])) 13 | 14 | (defn resolve 15 | "Given an analysis environment resolve a var. Analogous to 16 | clojure.core/resolve" 17 | [env sym] 18 | {:pre [(map? env) (symbol? sym)]} 19 | (try 20 | (ana/resolve-var env sym 21 | (ana/confirm-var-exists-throw)) 22 | (catch Exception e))) 23 | 24 | (defn all-ns 25 | "Return all the namespace analysis maps. Analagous to clojure.core/all-ns but 26 | returns analysis maps not Namespace instances." 27 | [] 28 | (keys (get @env/*compiler* ::ana/namespaces))) 29 | 30 | (defn find-ns 31 | "Given a namespace return the corresponding namespace analysis map. Analagous 32 | to clojure.core/find-ns." 33 | [sym] 34 | {:pre [(symbol? sym)]} 35 | (get-in @env/*compiler* [::ana/namespaces sym])) 36 | 37 | (defn ns-interns 38 | "Given a namespace return all the var analysis maps. Analagous to 39 | clojure.core/ns-interns but returns var analysis maps not vars." 40 | [ns] 41 | {:pre [(symbol? ns)]} 42 | (get-in @env/*compiler* [::ana/namespaces ns :defs])) 43 | 44 | (defn ns-resolve 45 | "Given a namespace and a symbol return the corresponding var analysis map. 46 | Analagous to clojure.core/ns-resolve but returns var analysis map not Var." 47 | [ns sym] 48 | {:pre [(symbol? ns) (symbol? sym)]} 49 | (get-in @env/*compiler* [::ana/namespaces ns :defs sym])) 50 | 51 | (defmacro in-cljs-user 52 | "Binds cljs.analyzer/*cljs-ns* to 'cljs.user and uses the given compilation 53 | environment atom and runs body." 54 | [env & body] 55 | `(binding [cljs.analyzer/*cljs-ns* 'cljs.user] 56 | (cljs.env/with-compiler-env ~env 57 | ~@body))) -------------------------------------------------------------------------------- /src/clj/cljs/analyzer/utils.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.analyzer.utils 10 | (:require [cljs.analyzer :as ana])) 11 | 12 | (defn simplify-env [_ {:keys [op] :as ast}] 13 | (let [env (:env ast) 14 | ast (if (= op :fn) 15 | (assoc ast :methods 16 | (map #(simplify-env nil %) (:methods ast))) 17 | ast)] 18 | (assoc (dissoc ast :env) 19 | :env {:context (:context env)}))) 20 | 21 | (defn elide-children [_ ast] 22 | (dissoc ast :children)) 23 | 24 | (defn to-ast 25 | ([form] (to-ast 'cljs.user form)) 26 | ([ns form] 27 | (let [env (assoc-in (ana/empty-env) [:ns :name] ns)] 28 | (binding [ana/*passes* 29 | (or ana/*passes* 30 | [elide-children simplify-env ana/infer-type])] 31 | (ana/analyze env form))))) 32 | 33 | (comment 34 | (require '[clojure.pprint :as pp]) 35 | (pp/pprint (to-ast '(defn foo [a b] (+ a b)))) 36 | ) 37 | -------------------------------------------------------------------------------- /src/clj/cljs/build/api.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software 8 | (ns cljs.build.api 9 | "This is intended to be a stable api for those who intend to create 10 | tools that use compiler data. 11 | 12 | For example: a build script may need to how to invalidate compiled 13 | files so that they will be recompiled." 14 | (:require [cljs.util :as util] 15 | [cljs.env :as env] 16 | [cljs.analyzer :as ana] 17 | [cljs.compiler :as comp] 18 | [cljs.closure :as closure] 19 | [clojure.set :refer [intersection]] 20 | [cljs.js-deps :as js-deps] 21 | [clojure.java.io :as io]) 22 | (:import java.io.File)) 23 | 24 | (defn ^File target-file-for-cljs-ns 25 | "Given an output directory and a clojurescript namespace return the 26 | compilation target file for that namespace. 27 | 28 | For example: 29 | (target-file-from-cljs-ns \"resources/out\" 'example.core) -> 30 | " 31 | ([ns-sym] (target-file-for-cljs-ns ns-sym nil)) 32 | ([ns-sym output-dir] 33 | (util/to-target-file 34 | (util/output-directory {:output-dir output-dir}) 35 | {:ns ns-sym}))) 36 | 37 | (defn mark-cljs-ns-for-recompile! 38 | "Backdates a cljs target file so that it the cljs compiler will recompile it." 39 | ([ns-sym] (mark-cljs-ns-for-recompile! ns-sym nil)) 40 | ([ns-sym output-dir] 41 | (let [s (target-file-for-cljs-ns output-dir ns-sym)] 42 | (when (.exists s) 43 | (.setLastModified s 5000))))) 44 | 45 | (defn cljs-dependents-for-macro-namespaces 46 | "Takes a list of Clojure (.clj) namespaces that define macros and 47 | returns a list ClojureScript (.cljs) namespaces that depend on those macro 48 | namespaces. 49 | 50 | For example where example.macros is defined in the clojure file 51 | \"example/macros.clj\" and both 'example.core and 'example.util are 52 | ClojureScript namespaces that require and use the macros from 53 | 'example.macros : 54 | (cljs-dependents-for-macro-namespaces 'example.macros) -> 55 | ('example.core 'example.util) 56 | 57 | This must be called when cljs.env/*compiler* is bound to the 58 | compile env that you are inspecting. See cljs.env/with-compile-env." 59 | [namespaces] 60 | (map :name 61 | (let [namespaces-set (set namespaces)] 62 | (filter (fn [x] (not-empty 63 | (intersection namespaces-set (-> x :require-macros vals set)))) 64 | (vals (:cljs.analyzer/namespaces @env/*compiler*)))))) 65 | 66 | (defn cljs-ns-dependents 67 | "Given a namespace symbol return a seq of all dependent 68 | namespaces sorted in dependency order. Will include 69 | transient dependents." 70 | [ns] 71 | (ana/ns-dependents ns)) 72 | 73 | (defn parse-js-ns 74 | "Given a Google Closure style JavaScript file or resource return the namespace 75 | information for the given file. Only returns the value extracted from the 76 | first provide statement." 77 | [f] 78 | (closure/parse-js-ns f)) 79 | 80 | (defn ^File src-file->target-file 81 | "Given a ClojureScript source file return the target file. May optionally 82 | provide build options with :output-dir specified." 83 | ([src] (closure/src-file->target-file src)) 84 | ([src opts] (closure/src-file->target-file src opts))) 85 | 86 | (defn ^String src-file->goog-require 87 | "Given a ClojureScript or Google Closure style JavaScript source file return 88 | the goog.require statement for it." 89 | ([src] (closure/src-file->goog-require src)) 90 | ([src options] 91 | (closure/src-file->goog-require src options))) 92 | 93 | (comment 94 | 95 | (def test-cenv (atom {})) 96 | (def test-env (assoc-in (ana/empty-env) [:ns :name] 'cljs.user)) 97 | 98 | (binding [ana/*cljs-ns* 'cljs.user] 99 | (env/with-compiler-env test-cenv 100 | (ana/no-warn 101 | (ana/analyze test-env 102 | '(ns cljs.user 103 | (:use [clojure.string :only [join]])))))) 104 | 105 | (env/with-compiler-env test-cenv 106 | (ns-dependents 'clojure.string)) 107 | 108 | (map 109 | #(target-file-for-cljs-ns % "out-dev") 110 | (env/with-compiler-env test-cenv 111 | (ns-dependents 'clojure.string))) 112 | ) -------------------------------------------------------------------------------- /src/clj/cljs/env.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "A namespace that exists solely to provide a place for \"compiler\" 10 | state that is accessed/maintained by many different components."} 11 | cljs.env 12 | (:require [cljs.js-deps :refer (js-dependency-index)]) 13 | (:refer-clojure :exclude [ensure])) 14 | 15 | ;; bit of a misnomer, but: an atom containing a map that serves as the bag of 16 | ;; state for the compiler, writ large (including analyzer, emitter, and 17 | ;; optimization stages). Each namespace has its own local var, to accommodate 18 | ;; multiple (lower-level) entry points. Any state needed by the compiler across 19 | ;; multiple applications should be put into this map/atom. Aside from 20 | ;; unfortunate current implementation details (e.g. depending on filesystem 21 | ;; state for certain things), the compiler should be idempotent with regard to 22 | ;; the environment passed to any entry point. 23 | ;; 24 | ;; Known slots in the compiler-env map: 25 | ;; 26 | ;; * :options - the [options] map argument, provided to this fn (defaults to {}) 27 | ;; * :js-dependency-index - result from calling cljs.js-deps/js-dependency-index 28 | ;; with [options] 29 | ;; * :cljs.analyzer/constant-table - map of (currently only keyword) constant 30 | ;; values to fixed ids 31 | ;; * :cljs.analyzer/namespaces - map of symbols to "namespace" maps 32 | ;; * :cljs.compiler/compiled-cljs - cache of intermediate compilation results 33 | ;; that speeds incremental builds in conjunction with source map generation 34 | ;; * :cljs.closure/compiled-cljs - cache from js file path to map of 35 | ;; {:file .. :provides .. :requires ..} 36 | ;; 37 | ;; Note that this var is functionally private to the compiler, and contains 38 | ;; implementation-dependent data. 39 | (def ^:dynamic *compiler* nil) 40 | 41 | (defn default-compiler-env 42 | ([] (default-compiler-env {})) 43 | ([options] 44 | (atom {:options options 45 | :js-dependency-index (js-dependency-index options)}))) 46 | 47 | (defmacro with-compiler-env 48 | "Evaluates [body] with [env] bound as the value of the `*compiler*` var in 49 | this namespace." 50 | [env & body] 51 | `(let [env# ~env 52 | env# (cond 53 | (map? env#) (atom env#) 54 | (and (instance? clojure.lang.Atom env#) 55 | (map? @env#)) env# 56 | :default (throw (IllegalArgumentException. 57 | (str "Compiler environment must be a map or atom containing a map, not " 58 | (class env#)))))] 59 | (binding [*compiler* env#] ~@body))) 60 | 61 | (defmacro ensure 62 | [& body] 63 | `(let [val# *compiler*] 64 | (if (nil? val#) 65 | (push-thread-bindings 66 | (hash-map (var *compiler*) (default-compiler-env)))) 67 | (try 68 | ~@body 69 | (finally 70 | (if (nil? val#) 71 | (pop-thread-bindings)))))) 72 | -------------------------------------------------------------------------------- /src/clj/cljs/repl/node_repl.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_DISABLE_COLORS = true; 2 | 3 | var net = require("net"); 4 | var PORT = 5001; 5 | 6 | try { 7 | require("source-map-support").install(); 8 | } catch(err) { 9 | } 10 | 11 | net.createServer(function (socket) { 12 | var buffer = "", 13 | ret = null, 14 | err = null; 15 | 16 | socket.setEncoding("utf8"); 17 | 18 | socket.on("data", function(data) { 19 | if(data[data.length-1] != "\0") { 20 | buffer += data; 21 | } else { 22 | if(buffer.length > 0) { 23 | data = buffer + data; 24 | buffer = ""; 25 | } 26 | if(data) { 27 | // not sure how \0's are getting through - David 28 | data = data.replace(/\0/g, ""); 29 | try { 30 | ret = process.binding('evals').NodeScript.runInThisContext.call( 31 | global, data, "repl"); 32 | } catch (e) { 33 | err = e; 34 | } 35 | } 36 | 37 | if(err) { 38 | socket.write(JSON.stringify({ 39 | status: "exception", 40 | value: err.stack 41 | })); 42 | } else if(ret !== undefined && ret !== null) { 43 | socket.write(JSON.stringify({ 44 | status: "success", 45 | value: ret.toString() 46 | })); 47 | } else { 48 | socket.write(JSON.stringify({ 49 | status: "success", 50 | value: null 51 | })); 52 | } 53 | 54 | ret = null; 55 | err = null; 56 | 57 | socket.write("\0"); 58 | } 59 | }); 60 | 61 | }).listen(PORT); 62 | 63 | console.log("ClojureScript Node.js REPL server listening on", PORT); 64 | -------------------------------------------------------------------------------- /src/clj/cljs/repl/reflect.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.repl.reflect 2 | (:refer-clojure :exclude [macroexpand]) 3 | (:require [cljs.repl.server :as server] 4 | [cljs.analyzer :as analyzer] 5 | [cljs.compiler :as compiler] 6 | [clojure.string :as str] 7 | [clojure.pprint :as pprint])) 8 | 9 | (defn- dissoc-unless 10 | "Dissoc all keys from map that do not appear in key-set. 11 | 12 | (dissoc-unless {:foo 1 :bar 2} #{:foo}) 13 | => {:foo 1}" 14 | [m key-set] 15 | {:pre [(map? m) 16 | (set? key-set)]} 17 | (reduce (fn [coll key] 18 | (if (contains? key-set key) 19 | coll 20 | (dissoc coll key))) 21 | m (keys m))) 22 | 23 | (defn- get-meta [sym] 24 | (let [ns (symbol (namespace sym)) 25 | n (symbol (name sym))] 26 | (if-let [sym-meta (get (:defs (get @analyzer/namespaces ns)) n)] 27 | (-> (dissoc-unless sym-meta 28 | #{:name :method-params :doc :line :file}) 29 | (update-in [:name] str) 30 | (update-in [:method-params] #(str (vec %))))))) 31 | 32 | (defn macroexpand [form] 33 | "Fully expands a cljs macro form." 34 | (let [mform (analyzer/macroexpand-1 {} form)] 35 | (if (identical? form mform) 36 | mform 37 | (macroexpand mform)))) 38 | 39 | (defn- url-decode [encoded & [encoding]] 40 | (java.net.URLDecoder/decode encoded (or encoding "UTF-8"))) 41 | 42 | (def read-url-string (comp read-string url-decode)) 43 | 44 | (defn parse-param 45 | "Parses the query parameter of a path of the form \"/reflect?var=foo\" 46 | into the vector [\"var\" \"foo\"]." 47 | [path] 48 | (-> (str/split path #"\?") 49 | (last) 50 | (str/split #"="))) 51 | 52 | (defn- compile-and-return 53 | "Compiles a form to javascript and returns it on conn." 54 | [conn form] 55 | (let [ast (analyzer/analyze {:ns {:name 'cljs.user}} form) 56 | js (try (compiler/emit-str ast) 57 | (catch Exception e (println e)))] 58 | (server/send-and-close conn 200 js "text/javascript"))) 59 | 60 | (defmulti handle-reflect-query (fn [[param _] & _] param)) 61 | 62 | (defmethod handle-reflect-query "var" 63 | [[_ sym] req conn opts] 64 | (let [sym (read-url-string sym)] 65 | (compile-and-return conn (get-meta sym)))) 66 | 67 | (defmethod handle-reflect-query "macroform" 68 | [[_ mform] req conn opts] 69 | (let [mform (-> mform read-url-string macroexpand)] 70 | (server/send-and-close conn 200 (with-out-str (pprint/pprint mform))))) 71 | 72 | (server/dispatch-on :get 73 | (fn [{:keys [path]} _ _] (.startsWith path "/reflect")) 74 | (fn [{:keys [path] :as req} conn opts] 75 | (handle-reflect-query (parse-param path) req conn opts))) 76 | -------------------------------------------------------------------------------- /src/clj/cljs/source_map/base64.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.source-map.base64) 2 | 3 | (def chars64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") 4 | (def char->int (zipmap chars64 (range 0 64))) 5 | (def int->char (zipmap (range 0 64) chars64)) 6 | 7 | (defn encode [n] 8 | (let [e (find int->char n)] 9 | (if e 10 | (second e) 11 | (throw (Error. (str "Must be between 0 and 63: " n)))))) 12 | 13 | (defn ^Character decode [c] 14 | (let [e (find char->int c)] 15 | (if e 16 | (second e) 17 | (throw (Error. (str "Not a valid base 64 digit: " c)))))) -------------------------------------------------------------------------------- /src/clj/cljs/source_map/base64_vlq.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.source-map.base64-vlq 2 | (require [clojure.string :as string] 3 | [cljs.source-map.base64 :as base64])) 4 | 5 | (def ^:const vlq-base-shift 5) 6 | (def ^:const vlq-base (bit-shift-left 1 vlq-base-shift)) 7 | (def ^:const vlq-base-mask (dec vlq-base)) 8 | (def ^:const vlq-continuation-bit vlq-base) 9 | 10 | (defn bit-shift-right-zero-fill [x n] 11 | (bit-shift-right (bit-and 0xFFFFFFFF x) n)) 12 | 13 | (defn to-vlq-signed [v] 14 | (if (neg? v) 15 | (inc (bit-shift-left (- v) 1)) 16 | (+ (bit-shift-left v 1) 0))) 17 | 18 | (defn from-vlq-signed [v] 19 | (let [neg? (= (bit-and v 1) 1) 20 | shifted (bit-shift-right v 1)] 21 | (if neg? 22 | (- shifted) 23 | shifted))) 24 | 25 | (defn encode-val [n] 26 | (let [sb (StringBuilder.) 27 | vlq (to-vlq-signed n)] 28 | (loop [digit (bit-and vlq vlq-base-mask) 29 | vlq (bit-shift-right-zero-fill vlq vlq-base-shift)] 30 | (if (pos? vlq) 31 | (let [digit (bit-or digit vlq-continuation-bit)] 32 | (.append sb (base64/encode digit)) 33 | (recur (bit-and vlq vlq-base-mask) 34 | (bit-shift-right-zero-fill vlq vlq-base-shift))) 35 | (.append sb (base64/encode digit)))) 36 | (str sb))) 37 | 38 | (defn encode [v] 39 | (apply str (map encode-val v))) 40 | 41 | (defn decode [^String s] 42 | (let [l (.length s)] 43 | (loop [i 0 result 0 shift 0] 44 | (when (>= i l) 45 | (throw (Error. "Expected more digits in base 64 VLQ value."))) 46 | (let [digit (base64/decode (.charAt s i))] 47 | (let [i (inc i) 48 | continuation? (pos? (bit-and digit vlq-continuation-bit)) 49 | digit (bit-and digit vlq-base-mask) 50 | result (+ result (bit-shift-left digit shift)) 51 | shift (+ shift vlq-base-shift)] 52 | (if continuation? 53 | (recur i result shift) 54 | (lazy-seq 55 | (cons (from-vlq-signed result) 56 | (let [s (.substring s i)] 57 | (when-not (string/blank? s) 58 | (decode s))))))))))) 59 | 60 | (comment 61 | ;; tests 62 | 63 | (bit-shift-right-zero-fill 127 1) ;; 63 64 | (bit-shift-right-zero-fill -127 1) ;; 2147483584 65 | 66 | (to-vlq-signed 32) ;; 64 67 | (to-vlq-signed -32) ;; 65 68 | (from-vlq-signed 64) ;; 32 69 | (from-vlq-signed 65) ;; -32 70 | 71 | ;; Base64 VLQ can only represent 32bit values 72 | 73 | (encode-val 32) ; "gC" 74 | (decode "gC") ; {:value 32 :rest ""} 75 | 76 | (decode "AAgBC") ; (0 0 16 1) 77 | 78 | ;; lines kept count by semicolons, segments delimited by commas 79 | ;; the above is gline 0, gcol 0, file 0, line 16, col 1, no name if this was the first segment read 80 | 81 | (decode "AAggBC") ; very clever way to encode large values 82 | (decode "AAggBCA") ; 5 values instead of 4 83 | 84 | (encode [0 0 16 1]) ; "AAgBC" 85 | 86 | (decode "IAWdD") ; (4 0 11 -14 -1) this is correct 87 | ;; gline N, gcol +4, file +0, line +11, col -14, name -1 88 | 89 | ;; Notes about format 90 | ;; we always have 1, 4, or 5 values, all zero-based indexes 91 | ;; 1. generated col - relative - reset on every new line in generated source 92 | ;; 2. index into sources list - relative 93 | ;; 3. original line - relative 94 | ;; 4. origin column - relative 95 | ;; 5. name - relative 96 | ) -------------------------------------------------------------------------------- /src/clj/cljs/tagged_literals.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.tagged-literals 2 | (:require [clojure.instant :as inst])) 3 | 4 | (defn read-queue 5 | [form] 6 | (when-not (vector? form) 7 | (throw (RuntimeException. "Queue literal expects a vector for its elements."))) 8 | (list 'cljs.core/into 'cljs.core.PersistentQueue.EMPTY form)) 9 | 10 | (defn read-uuid 11 | [form] 12 | (when-not (string? form) 13 | (throw (RuntimeException. "UUID literal expects a string as its representation."))) 14 | (try 15 | (java.util.UUID/fromString form) 16 | (catch Throwable e 17 | (throw (RuntimeException. (.getMessage e)))))) 18 | 19 | (defn read-inst 20 | [form] 21 | (when-not (string? form) 22 | (throw (RuntimeException. "Instance literal expects a string for its timestamp."))) 23 | (try 24 | (inst/read-instant-date form) 25 | (catch Throwable e 26 | (throw (RuntimeException. (.getMessage e)))))) 27 | 28 | (defn valid-js-literal-key? [k] 29 | (or (string? k) 30 | (and (keyword? k) 31 | (nil? (namespace k))))) 32 | 33 | (deftype JSValue [val]) 34 | 35 | (defn read-js 36 | [form] 37 | (when-not (or (vector? form) (map? form)) 38 | (throw (RuntimeException. "JavaScript literal must use map or vector notation"))) 39 | (when-not (or (not (map? form)) 40 | (every? valid-js-literal-key? (keys form))) 41 | (throw (RuntimeException. "JavaScript literal keys must be strings or unqualified keywords"))) 42 | (JSValue. form)) 43 | 44 | (def ^:dynamic *cljs-data-readers* 45 | {'queue read-queue 46 | 'uuid read-uuid 47 | 'inst read-inst 48 | 'js read-js}) 49 | -------------------------------------------------------------------------------- /src/clj/cljs/util.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.util 10 | (:require [clojure.java.io :as io] 11 | [clojure.string :as string] 12 | [clojure.edn :as edn]) 13 | (:import [java.io File] 14 | [java.net URL])) 15 | 16 | ;; next line is auto-generated by the build-script - Do not edit! 17 | (def ^:dynamic *clojurescript-version* {:major 0, :minor 0, :qualifier 2694}) 18 | 19 | (defn ^String clojurescript-version 20 | "Returns clojurescript version as a printable string." 21 | [] 22 | (if (bound? #'*clojurescript-version*) 23 | (str 24 | (:major *clojurescript-version*) 25 | "." 26 | (:minor *clojurescript-version*) 27 | (when-let [i (:incremental *clojurescript-version*)] 28 | (str "." i)) 29 | (when-let [q (:qualifier *clojurescript-version*)] 30 | (str "-" q)) 31 | (when (:interim *clojurescript-version*) 32 | "-SNAPSHOT")) 33 | "0.0-0000")) 34 | 35 | (defn ^String compiled-by-version [^File f] 36 | (with-open [reader (io/reader f)] 37 | (let [match (->> reader line-seq first 38 | (re-matches #".*ClojureScript (\d+\.\d+-\d+).*$"))] 39 | (or (and match (second match)) "0.0-0000")))) 40 | 41 | (defn build-options [^File f] 42 | (with-open [reader (io/reader f)] 43 | (let [match (->> reader line-seq first 44 | (re-matches #".*ClojureScript \d+\.\d+-\d+ (.*)$"))] 45 | (and match (edn/read-string (second match)))))) 46 | 47 | (defn munge-path [ss] 48 | (clojure.lang.Compiler/munge (str ss))) 49 | 50 | (defn ns->relpath [s] 51 | (str (string/replace (munge-path s) \. \/) ".cljs")) 52 | 53 | (defn path-seq 54 | [file-str] 55 | (->> File/separator 56 | java.util.regex.Pattern/quote 57 | re-pattern 58 | (string/split file-str))) 59 | 60 | (defn to-path 61 | ([parts] 62 | (to-path parts File/separator)) 63 | ([parts sep] 64 | (apply str (interpose sep parts)))) 65 | 66 | (defn ^File to-target-file 67 | ([target-dir ns-info] 68 | (to-target-file target-dir ns-info "js")) 69 | ([target-dir ns-info ext] 70 | (let [relative-path (string/split (munge-path (str (:ns ns-info))) #"\.") 71 | parents (cond-> (butlast relative-path) 72 | target-dir (conj target-dir))] 73 | (io/file (io/file (to-path parents)) 74 | (str (last relative-path) (str "." ext)))))) 75 | 76 | (defn mkdirs 77 | "Create all parent directories for the passed file." 78 | [^File f] 79 | (.mkdirs (.getParentFile (.getCanonicalFile f)))) 80 | 81 | (defn output-directory 82 | ([opts] (output-directory opts "out")) 83 | ([opts default] 84 | (or (:output-dir opts) default))) 85 | 86 | (defn file? [f] 87 | (instance? File f)) 88 | 89 | (defn url? [f] 90 | (instance? URL f)) 91 | 92 | (defn ^String filename [^File f] 93 | (.getName f)) 94 | 95 | (defn ^String path [^URL url] 96 | (.getPath url)) 97 | 98 | (defn ^String ext 99 | "Given a file or url return the file extension." 100 | [f] 101 | (let [s (cond 102 | (file? f) (filename f) 103 | (url? f) (path f))] 104 | (last (string/split s #"\.")))) 105 | 106 | (defn debug-prn 107 | [& args] 108 | (.println System/err (apply str args))) 109 | 110 | (defmacro measure 111 | "Like cljs.core/time but toggleable and takes a message string." 112 | {:added "1.0"} 113 | ([msg expr] `(measure true ~msg ~expr)) 114 | ([enable msg expr] 115 | `(if ~enable 116 | (let [start# (. System (nanoTime)) 117 | ret# ~expr] 118 | (debug-prn (str ~msg ", elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs")) 119 | (debug-prn "") 120 | ret#) 121 | ~expr))) 122 | -------------------------------------------------------------------------------- /src/cljs/cljs/bootstrap_node.js: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Closure Library Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS-IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** 16 | * @fileoverview A nodejs script for dynamically requiring Closure within 17 | * nodejs. 18 | * 19 | * Example of usage: 20 | * 21 | * require('./bootstrap/nodejs') 22 | * goog.require('goog.ui.Component') 23 | * 24 | * 25 | * This loads goog.ui.Component in the global scope. 26 | * 27 | * If you want to load custom libraries, you can require the custom deps file 28 | * directly. If your custom libraries introduce new globals, you may 29 | * need to run goog.nodeGlobalRequire to get them to load correctly. 30 | * 31 | * 32 | * require('./path/to/my/deps.js') 33 | * goog.bootstrap.nodeJs.nodeGlobalRequire('./path/to/my/base.js') 34 | * goog.require('my.Class') 35 | * 36 | * 37 | * @author nick@medium.com (Nick Santos) 38 | * 39 | * @nocompile 40 | */ 41 | 42 | 43 | var fs = require('fs'); 44 | var path = require('path'); 45 | var CLJS_ROOT = "./"; 46 | 47 | 48 | /** 49 | * The goog namespace in the global scope. 50 | */ 51 | global.goog = {}; 52 | 53 | 54 | /** 55 | * Imports a script using Node's require() API. 56 | * 57 | * @param {string} src The script source. 58 | * @return {boolean} True if the script was imported, false otherwise. 59 | */ 60 | global.CLOSURE_IMPORT_SCRIPT = function(src) { 61 | // Sources are always expressed relative to closure's base.js, but 62 | // require() is always relative to the current source. 63 | if(CLJS_ROOT !== ".") { 64 | var path = null; 65 | if(src.substring(0, 3) == "../") { 66 | path = CLJS_ROOT+src.substring(3); 67 | } else { 68 | path = CLJS_ROOT+"goog/"+src; 69 | } 70 | if(require.cache[path]) delete require.cache[path]; 71 | } 72 | require('./../' + src); 73 | return true; 74 | }; 75 | 76 | 77 | // Declared here so it can be used to require base.js 78 | function nodeGlobalRequire(file) { 79 | process.binding('evals').NodeScript.runInThisContext.call( 80 | global, fs.readFileSync(file), file); 81 | } 82 | 83 | 84 | // Load Closure's base.js into memory. It is assumed base.js is in the 85 | // directory above this directory given this script's location in 86 | // bootstrap/nodejs.js. 87 | nodeGlobalRequire(path.resolve(__dirname, '..', 'base.js')); 88 | 89 | 90 | /** 91 | * Bootstraps a file into the global scope. 92 | * 93 | * This is strictly for cases where normal require() won't work, 94 | * because the file declares global symbols with 'var' that need to 95 | * be added to the global scope. 96 | * @suppress {missingProvide} 97 | * 98 | * @param {string} file The path to the file. 99 | */ 100 | goog.nodeGlobalRequire = nodeGlobalRequire; 101 | 102 | -------------------------------------------------------------------------------- /src/cljs/cljs/externs.js: -------------------------------------------------------------------------------- 1 | Math.imul = function(a, b) {}; 2 | 3 | var cljs = {}; 4 | cljs.core = {}; 5 | /** 6 | * @constructor; 7 | */ 8 | cljs.core.Iterator = function() {}; 9 | cljs.core.Iterator.prototype.next = function() {}; 10 | 11 | /** 12 | * @constructor; 13 | */ 14 | function IteratorStep() {}; 15 | /** 16 | * @type {boolean} 17 | */ 18 | IteratorStep.prototype.done; 19 | /** 20 | * @type {Object} 21 | */ 22 | IteratorStep.prototype.value; 23 | 24 | /** 25 | * @constructor; 26 | */ 27 | function Map() {}; 28 | Map.prototype.keys = function() {}; 29 | Map.prototype.entries = function() {}; 30 | Map.prototype.values = function() {}; 31 | Map.prototype.has = function(k) {}; 32 | Map.prototype.get = function(k) {}; 33 | Map.prototype.forEach = function(f) {}; 34 | 35 | /** 36 | * @constructor; 37 | */ 38 | function Set() {}; 39 | Set.prototype.keys = function() {}; 40 | Set.prototype.entries = function() {}; 41 | Set.prototype.values = function() {}; 42 | Set.prototype.has = function(k) {}; 43 | Set.prototype.forEach = function(f) {}; 44 | 45 | /** 46 | * @constructor; 47 | */ 48 | function IEquiv() {}; 49 | IEquiv.prototype.equiv = function() {}; 50 | -------------------------------------------------------------------------------- /src/cljs/cljs/imul.js: -------------------------------------------------------------------------------- 1 | if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) { 2 | Math.imul = function (a, b) { 3 | var ah = (a >>> 16) & 0xffff; 4 | var al = a & 0xffff; 5 | var bh = (b >>> 16) & 0xffff; 6 | var bl = b & 0xffff; 7 | // the shift by 0 fixes the sign on the high part 8 | // the final |0 converts the unsigned value into a signed value 9 | return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cljs/cljs/nodejs.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | ; Projects compiled with :target :nodejs can 'require' this namespace 10 | ; to get the nodejs globals loaded into cljs.nodejs and get 11 | ; ClojureScript's 'print' set up correctly. 12 | (ns cljs.nodejs) 13 | 14 | ; Define namespaced references to Node's externed globals: 15 | (def require (js* "require")) 16 | (def process (js* "process")) 17 | 18 | ; Have ClojureScript print using Node's sys.print function 19 | (defn enable-util-print! [] 20 | (set! *print-fn* (.-print (require "util")))) 21 | -------------------------------------------------------------------------------- /src/cljs/cljs/nodejs_externs.js: -------------------------------------------------------------------------------- 1 | function require(){} 2 | function process(){} 3 | -------------------------------------------------------------------------------- /src/cljs/cljs/nodejscli.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | ; Projects compiled with :target :nodejs have this file appended. Its 10 | ; job is to make sure cljs.nodejs is loaded and that the *main-cli-fn* 11 | ; is called with the script's command-line arguments. 12 | (ns cljs.nodejscli 13 | (:require [cljs.nodejs :as nodejs])) 14 | 15 | ; Call the user's main function 16 | (apply cljs.core/*main-cli-fn* (drop 2 (.-argv nodejs/process))) 17 | 18 | -------------------------------------------------------------------------------- /src/cljs/cljs/pprint.clj: -------------------------------------------------------------------------------- 1 | ;;; pprint.clj -- Pretty printer and Common Lisp compatible format function (cl-format) for Clojure 2 | 3 | ; Copyright (c) Rich Hickey. All rights reserved. 4 | ; The use and distribution terms for this software are covered by the 5 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 6 | ; which can be found in the file epl-v10.html at the root of this distribution. 7 | ; By using this software in any fashion, you are agreeing to be bound by 8 | ; the terms of this license. 9 | ; You must not remove this notice, or any other, from this software. 10 | 11 | ;; Author: Tom Faulhaber 12 | ;; April 3, 2009 13 | 14 | (ns cljs.pprint) 15 | 16 | (defmacro ^{:private true} prlabel [prefix arg & more-args] 17 | "Print args to *err* in name = value format" 18 | `(prerr ~@(cons (list 'quote prefix) (mapcat #(list (list 'quote %) "=" %) 19 | (cons arg (seq more-args)))))) 20 | -------------------------------------------------------------------------------- /src/cljs/cljs/pprint.cljs: -------------------------------------------------------------------------------- 1 | ;;; pprint.cljs -- Pretty printer and Common Lisp compatible format function (cl-format) for Clojure 2 | 3 | ; Copyright (c) Rich Hickey. All rights reserved. 4 | ; The use and distribution terms for this software are covered by the 5 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 6 | ; which can be found in the file epl-v10.html at the root of this distribution. 7 | ; By using this software in any fashion, you are agreeing to be bound by 8 | ; the terms of this license. 9 | ; You must not remove this notice, or any other, from this software. 10 | 11 | ;; Author: Tom Faulhaber 12 | ;; April 3, 2009 13 | 14 | (ns 15 | ^{:author "Tom Faulhaber", 16 | :doc "A Pretty Printer for ClojureScript 17 | 18 | cljs.pprint implements a flexible system for printing structured data 19 | in a pleasing, easy-to-understand format. Basic use of the pretty printer is 20 | simple, just call pprint instead of println. More advanced users can use 21 | the building blocks provided to create custom output formats. 22 | 23 | Out of the box, pprint supports a simple structured format for basic data 24 | and a specialized format for Clojure source code. More advanced formats, 25 | including formats that don't look like Clojure data at all like XML and 26 | JSON, can be rendered by creating custom dispatch functions. 27 | 28 | In addition to the pprint function, this module contains cl-format, a text 29 | formatting function which is fully compatible with the format function in 30 | Common Lisp. Because pretty printing directives are directly integrated with 31 | cl-format, it supports very concise custom dispatch. It also provides 32 | a more powerful alternative to Clojure's standard format function. 33 | 34 | See documentation for pprint and cl-format for more information or 35 | complete documentation on the the clojure web site on github."} 36 | cljs.pprint 37 | (:require [clojure.walk :refer [walk]])) 38 | 39 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 40 | ;;; Helper functions for digesting formats in the various 41 | ;;; phases of their lives. 42 | ;;; These functions are actually pretty general. 43 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 44 | 45 | (defn- map-passing-context [func initial-context lis] 46 | (loop [context initial-context 47 | lis lis 48 | acc []] 49 | (if (empty? lis) 50 | [acc context] 51 | (let [this (first lis) 52 | remainder (next lis) 53 | [result new-context] (apply func [this context])] 54 | (recur new-context remainder (conj acc result)))))) 55 | 56 | (defn- consume [func initial-context] 57 | (loop [context initial-context 58 | acc []] 59 | (let [[result new-context] (apply func [context])] 60 | (if (not result) 61 | [acc new-context] 62 | (recur new-context (conj acc result)))))) 63 | 64 | (defn- consume-while [func initial-context] 65 | (loop [context initial-context 66 | acc []] 67 | (let [[result continue new-context] (apply func [context])] 68 | (if (not continue) 69 | [acc context] 70 | (recur new-context (conj acc result)))))) 71 | 72 | (defn- unzip-map [m] 73 | "Take a map that has pairs in the value slots and produce a pair of maps, 74 | the first having all the first elements of the pairs and the second all 75 | the second elements of the pairs" 76 | [(into {} (for [[k [v1 v2]] m] [k v1])) 77 | (into {} (for [[k [v1 v2]] m] [k v2]))]) 78 | 79 | (defn- tuple-map [m v1] 80 | "For all the values, v, in the map, replace them with [v v1]" 81 | (into {} (for [[k v] m] [k [v v1]]))) 82 | 83 | (defn- rtrim [s c] 84 | "Trim all instances of c from the end of sequence s" 85 | (let [len (count s)] 86 | (if (and (pos? len) (= (nth s (dec (count s))) c)) 87 | (loop [n (dec len)] 88 | (cond 89 | (neg? n) "" 90 | (not (= (nth s n) c)) (subs s 0 (inc n)) 91 | true (recur (dec n)))) 92 | s))) 93 | 94 | (defn- ltrim [s c] 95 | "Trim all instances of c from the beginning of sequence s" 96 | (let [len (count s)] 97 | (if (and (pos? len) (= (nth s 0) c)) 98 | (loop [n 0] 99 | (if (or (= n len) (not (= (nth s n) c))) 100 | (subs s n) 101 | (recur (inc n)))) 102 | s))) 103 | 104 | (defn- prefix-count [aseq val] 105 | "Return the number of times that val occurs at the start of sequence aseq, 106 | if val is a seq itself, count the number of times any element of val occurs at the 107 | beginning of aseq" 108 | (let [test (if (coll? val) (set val) #{val})] 109 | (loop [pos 0] 110 | (if (or (= pos (count aseq)) (not (test (nth aseq pos)))) 111 | pos 112 | (recur (inc pos)))))) 113 | 114 | (defn- prerr [& args] 115 | "Println to *err*" 116 | ;; there is no *err* yet 117 | (apply println args)) 118 | 119 | ;; Flush the pretty-print buffer without flushing the underlying stream 120 | (defprotocol PrettyFlush (ppflush [this])) 121 | -------------------------------------------------------------------------------- /src/cljs/cljs/repl.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.repl) 10 | 11 | (defn print-doc [m] 12 | (println "-------------------------") 13 | (println (str (when-let [ns (:ns m)] (str ns "/")) (:name m))) 14 | (cond 15 | (:forms m) (doseq [f (:forms m)] 16 | (print " ") 17 | (prn f)) 18 | (:arglists m) (prn (:arglists m))) 19 | (if (:special-form m) 20 | (do 21 | (println "Special Form") 22 | (println " " (:doc m)) 23 | (if (contains? m :url) 24 | (when (:url m) 25 | (println (str "\n Please see http://clojure.org/" (:url m)))) 26 | (println (str "\n Please see http://clojure.org/special_forms#" 27 | (:name m))))) 28 | (do 29 | (when (:macro m) 30 | (println "Macro")) 31 | (println " " (:doc m))))) 32 | -------------------------------------------------------------------------------- /src/cljs/cljs/source_map/base64.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.source-map.base64) 10 | 11 | (def chars64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") 12 | (def char->int (zipmap chars64 (range 0 64))) 13 | (def int->char (zipmap (range 0 64) chars64)) 14 | 15 | (defn encode [n] 16 | (let [e (find int->char n)] 17 | (if e 18 | (second e) 19 | (throw (js/Error. (str "Must be between 0 and 63: " n)))))) 20 | 21 | (defn decode [c] 22 | (let [e (find char->int c)] 23 | (if e 24 | (second e) 25 | (throw (js/Error. (str "Not a valid base 64 digit: " c)))))) 26 | -------------------------------------------------------------------------------- /src/cljs/cljs/source_map/base64_vlq.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns cljs.source-map.base64-vlq 10 | (:require [clojure.string :as string] 11 | [cljs.source-map.base64 :as base64]) 12 | (:import [goog.string StringBuffer])) 13 | 14 | (def ^:const vlq-base-shift 5) 15 | (def ^:const vlq-base (bit-shift-left 1 vlq-base-shift)) 16 | (def ^:const vlq-base-mask (dec vlq-base)) 17 | (def ^:const vlq-continuation-bit vlq-base) 18 | 19 | (defn to-vlq-signed [v] 20 | (if (neg? v) 21 | (inc (bit-shift-left (- v) 1)) 22 | (+ (bit-shift-left v 1) 0))) 23 | 24 | (defn from-vlq-signed [v] 25 | (let [neg? (= (bit-and v 1) 1) 26 | shifted (bit-shift-right v 1)] 27 | (if neg? 28 | (- shifted) 29 | shifted))) 30 | 31 | (defn encode-val [n] 32 | (let [sb (StringBuffer.) 33 | vlq (to-vlq-signed n)] 34 | (loop [digit (bit-and vlq vlq-base-mask) 35 | vlq (bit-shift-right-zero-fill vlq vlq-base-shift)] 36 | (if (pos? vlq) 37 | (let [digit (bit-or digit vlq-continuation-bit)] 38 | (.append sb (base64/encode digit)) 39 | (recur (bit-and vlq vlq-base-mask) 40 | (bit-shift-right-zero-fill vlq vlq-base-shift))) 41 | (.append sb (base64/encode digit)))) 42 | (str sb))) 43 | 44 | (defn encode [v] 45 | (apply str (map encode-val v))) 46 | 47 | (defn decode [s] 48 | (let [l (.-length s)] 49 | (loop [i 0 result 0 shift 0] 50 | (when (>= i l) 51 | (throw (js/Error. "Expected more digits in base 64 VLQ value."))) 52 | (let [digit (base64/decode (.charAt s i))] 53 | (let [i (inc i) 54 | continuation? (pos? (bit-and digit vlq-continuation-bit)) 55 | digit (bit-and digit vlq-base-mask) 56 | result (+ result (bit-shift-left digit shift)) 57 | shift (+ shift vlq-base-shift)] 58 | (if continuation? 59 | (recur i result shift) 60 | (lazy-seq 61 | (cons (from-vlq-signed result) 62 | (let [s (.substring s i)] 63 | (when-not (string/blank? s) 64 | (decode s))))))))))) 65 | 66 | (comment 67 | ;; tests 68 | 69 | (bit-shift-right-zero-fill 127 1) ;; 63 70 | (bit-shift-right-zero-fill -127 1) ;; 2147483584 71 | 72 | (to-vlq-signed 32) ;; 64 73 | (to-vlq-signed -32) ;; 65 74 | (from-vlq-signed 64) ;; 32 75 | (from-vlq-signed 65) ;; -32 76 | 77 | ;; Base64 VLQ can only represent 32bit values 78 | 79 | (encode-val 32) ; "gC" 80 | (decode "gC") ; {:value 32 :rest ""} 81 | 82 | (decode "AAgBC") ; (0 0 16 1) 83 | 84 | ;; lines kept count by semicolons, segments delimited by commas 85 | ;; the above is gline 0, gcol 0, file 0, line 16, col 1, no name if this was the first segment read 86 | 87 | (decode "AAggBC") ; very clever way to encode large values 88 | (decode "AAggBCA") ; 5 values instead of 4 89 | 90 | (encode [0 0 16 1]) ; "AAgBC" 91 | 92 | (decode "IAWdD") ; (4 0 11 -14 -1) this is correct 93 | ;; gline N, gcol +4, file +0, line +11, col -14, name -1 94 | 95 | ;; Notes about format 96 | ;; we always have 1, 4, or 5 values, all zero-based indexes 97 | ;; 1. generated col - relative - reset on every new line in generated source 98 | ;; 2. index into sources list - relative 99 | ;; 3. original line - relative 100 | ;; 4. origin column - relative 101 | ;; 5. name - relative 102 | ) 103 | -------------------------------------------------------------------------------- /src/cljs/clojure/browser/dom.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.browser.dom 10 | (:require [goog.dom :as gdom] 11 | [goog.object :as gobject])) 12 | 13 | (defn append [parent & children] 14 | (apply gdom/append parent children) 15 | parent) 16 | 17 | (defprotocol DOMBuilder 18 | (-element [this] [this attrs-or-children] [this attrs children])) 19 | 20 | (defn log [& args] 21 | (.log js/console (apply pr-str args))) 22 | 23 | (defn log-obj [obj] 24 | (.log js/console obj)) 25 | 26 | (extend-protocol DOMBuilder 27 | 28 | string 29 | (-element 30 | ([this] 31 | (log "string (-element " this ")") 32 | (cond (keyword? this) (gdom/createElement (name this)) 33 | :else (gdom/createTextNode (name this)))) 34 | 35 | ([this attrs-or-children] 36 | (log "string (-element " this " " attrs-or-children ")") 37 | (let [attrs (first attrs-or-children)] 38 | (if (map? attrs) 39 | (-element this attrs (rest attrs-or-children)) 40 | (-element this nil attrs-or-children)))) 41 | 42 | ([this attrs children] 43 | (log "string (-element " this " " attrs " " children ")") 44 | (let [str-attrs (if (and (map? attrs) (seq attrs)) 45 | (reduce (fn [o [k v]] 46 | (let [o (if (nil? o) (js-obj) o)] 47 | (log "o = " o) 48 | (log "k = " k) 49 | (log "v = " v) 50 | (when (or (keyword? k) 51 | (string? k)) 52 | (doto o (aset (name k) v))))) 53 | (js-obj) 54 | attrs) 55 | nil)] 56 | (log-obj str-attrs) 57 | (if (seq children) 58 | (apply gdom/createDom 59 | (name this) 60 | str-attrs 61 | (map -element children)) 62 | (gdom/createDom (name this) 63 | str-attrs))))) 64 | 65 | PersistentVector 66 | (-element 67 | [this] 68 | (log "PersistentVector (-element " this ")") 69 | (let [tag (first this) 70 | attrs (second this) 71 | children (drop 2 this)] 72 | (if (map? attrs) 73 | (-element tag attrs children) 74 | (-element tag nil (rest this))))) 75 | 76 | js/Element 77 | (-element [this] 78 | (log "js/Element (-element " this ")") 79 | this)) 80 | 81 | (defn element 82 | ([tag-or-text] 83 | (log "(element " tag-or-text ")") 84 | (-element tag-or-text)) 85 | ([tag & children] 86 | (log "(element " tag " " children ")") 87 | (let [attrs (first children)] 88 | (if (map? attrs) 89 | (-element tag attrs (rest children)) 90 | (-element tag nil children))))) 91 | 92 | (defn remove-children 93 | "Remove all children from the element with the passed id." 94 | [id] 95 | (let [parent (gdom/getElement (name id))] 96 | (do (gdom/removeChildren parent)))) 97 | 98 | (defn get-element [id] 99 | (gdom/getElement (name id))) 100 | 101 | (defn html->dom [s] 102 | (gdom/htmlToDocumentFragment s)) 103 | 104 | (defn insert-at [parent child index] 105 | (gdom/insertChildAt parent child index)) 106 | 107 | (defn ensure-element 108 | "Coerce the argument to a dom element if possible." 109 | [e] 110 | (cond (keyword? e) (get-element e) 111 | (string? e) (html->dom e) 112 | :else e)) 113 | 114 | (defn replace-node 115 | "Replace old-node with new-node. old-node can be an element or a 116 | keyword which is the id of the node to replace. new-node can be an 117 | element or an html string." 118 | [old-node new-node] 119 | (let [old-node (ensure-element old-node) 120 | new-node (ensure-element new-node)] 121 | (gdom/replaceNode new-node old-node) 122 | new-node)) 123 | 124 | (defn set-text 125 | "Set the text content for the passed element returning the 126 | element. If a keyword is passed in the place of e, the element with 127 | that id will be used and returned." 128 | [e s] 129 | (gdom/setTextContent (ensure-element e) s)) 130 | 131 | (defn get-value 132 | "Get the value of an element." 133 | [e] 134 | (.-value (ensure-element e))) 135 | 136 | (defn set-properties 137 | "Set properties on an element" 138 | [e m] 139 | (gdom/setProperties (ensure-element e) 140 | (apply gobject/create (interleave (keys m) (vals m))))) 141 | 142 | (defn set-value 143 | "Set the value property for an element." 144 | [e v] 145 | (set-properties e {"value" v})) 146 | 147 | (defn click-element 148 | [e] 149 | (.click (ensure-element e) ())) 150 | 151 | ;; TODO CSS class manipulation 152 | ;; TODO Query syntax 153 | -------------------------------------------------------------------------------- /src/cljs/clojure/browser/event.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "This namespace contains functions to work with browser 10 | events. It is based on the Google Closure Library event system." 11 | :author "Bobby Calderwood"} 12 | clojure.browser.event 13 | (:require [goog.events :as events]) 14 | (:import (goog.events EventTarget EventType))) 15 | 16 | (defprotocol IEventType 17 | (event-types [this])) 18 | 19 | (extend-protocol IEventType 20 | 21 | EventTarget 22 | (event-types 23 | [this] 24 | (into {} 25 | (map 26 | (fn [[k v]] 27 | [(keyword (.toLowerCase k)) 28 | v]) 29 | (merge 30 | (js->clj EventType)))))) 31 | 32 | (when (exists? js/Element) 33 | (extend-protocol IEventType 34 | 35 | js/Element 36 | (event-types 37 | [this] 38 | (into {} 39 | (map 40 | (fn [[k v]] 41 | [(keyword (.toLowerCase k)) 42 | v]) 43 | (merge 44 | (js->clj EventType))))))) 45 | 46 | (defn listen 47 | ([src type fn] 48 | (listen src type fn false)) 49 | ([src type fn capture?] 50 | (events/listen src 51 | (get (event-types src) type type) 52 | fn 53 | capture?))) 54 | 55 | (defn listen-once 56 | ([src type fn] 57 | (listen-once src type fn false)) 58 | ([src type fn capture?] 59 | (events/listenOnce src 60 | (get (event-types src) type type) 61 | fn 62 | capture?))) 63 | 64 | (defn unlisten 65 | ([src type fn] 66 | (unlisten src type fn false)) 67 | ([src type fn capture?] 68 | (events/unlisten src 69 | (get (event-types src) type type) 70 | fn 71 | capture?))) 72 | 73 | (defn unlisten-by-key 74 | [key] 75 | (events/unlistenByKey key)) 76 | 77 | (defn dispatch-event 78 | [src event] 79 | (events/dispatchEvent src event)) 80 | 81 | (defn expose [e] 82 | (events/expose e)) 83 | 84 | (defn fire-listeners 85 | [obj type capture event]) 86 | 87 | (defn total-listener-count [] 88 | (events/getTotalListenerCount)) 89 | 90 | ;; TODO 91 | (defn get-listener [src type listener opt_capt opt_handler]); ⇒ ?Listener 92 | (defn all-listeners [obj type capture]); ⇒ Array. 93 | 94 | (defn unique-event-id [event-type]); ⇒ string 95 | 96 | (defn has-listener [obj opt_type opt_capture]); ⇒ boolean 97 | ;; TODO? (defn listen-with-wrapper [src wrapper listener opt_capt opt_handler]) 98 | ;; TODO? (defn protect-browser-event-entry-point [errorHandler]) 99 | 100 | (defn remove-all [opt_obj opt_type opt_capt]); ⇒ number 101 | ;; TODO? (defn unlisten-with-wrapper [src wrapper listener opt_capt opt_handler]) 102 | -------------------------------------------------------------------------------- /src/cljs/clojure/browser/net.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "Network communication library, wrapping goog.net. 10 | Includes a common API over XhrIo, CrossPageChannel, and Websockets." 11 | :author "Bobby Calderwood and Alex Redington"} 12 | clojure.browser.net 13 | (:require [clojure.browser.event :as event] 14 | [goog.json :as gjson]) 15 | (:import (goog.net XhrIo EventType) 16 | (goog.net.xpc CfgFields CrossPageChannel) 17 | goog.Uri)) 18 | 19 | (def *timeout* 10000) 20 | 21 | (def event-types 22 | (into {} 23 | (map 24 | (fn [[k v]] 25 | [(keyword (.toLowerCase k)) 26 | v]) 27 | (merge 28 | (js->clj EventType))))) 29 | 30 | (defprotocol IConnection 31 | (connect 32 | [this] 33 | [this opt1] 34 | [this opt1 opt2] 35 | [this opt1 opt2 opt3]) 36 | (transmit 37 | [this opt] 38 | [this opt opt2] 39 | [this opt opt2 opt3] 40 | [this opt opt2 opt3 opt4] 41 | [this opt opt2 opt3 opt4 opt5]) 42 | (close [this])) 43 | 44 | (extend-type XhrIo 45 | 46 | IConnection 47 | (transmit 48 | ([this uri] 49 | (transmit this uri "GET" nil nil *timeout*)) 50 | ([this uri method] 51 | (transmit this uri method nil nil *timeout*)) 52 | ([this uri method content] 53 | (transmit this uri method content nil *timeout*)) 54 | ([this uri method content headers] 55 | (transmit this uri method content headers *timeout*)) 56 | ([this uri method content headers timeout] 57 | (.setTimeoutInterval this timeout) 58 | (.send this uri method content headers))) 59 | 60 | 61 | event/IEventType 62 | (event-types [this] 63 | (into {} 64 | (map 65 | (fn [[k v]] 66 | [(keyword (.toLowerCase k)) 67 | v]) 68 | (merge 69 | (js->clj EventType)))))) 70 | 71 | ;; TODO jQuery/sinatra/RestClient style API: (get [uri]), (post [uri payload]), (put [uri payload]), (delete [uri]) 72 | 73 | (def xpc-config-fields 74 | (into {} 75 | (map 76 | (fn [[k v]] 77 | [(keyword (.toLowerCase k)) 78 | v]) 79 | (js->clj CfgFields)))) 80 | 81 | (defn xhr-connection 82 | "Returns an XhrIo connection" 83 | [] 84 | (XhrIo.)) 85 | 86 | (defprotocol ICrossPageChannel 87 | (register-service [this service-name fn] [this service-name fn encode-json?])) 88 | 89 | (extend-type CrossPageChannel 90 | 91 | ICrossPageChannel 92 | (register-service 93 | ([this service-name fn] 94 | (register-service this service-name fn false)) 95 | ([this service-name fn encode-json?] 96 | (.registerService this (name service-name) fn encode-json?))) 97 | 98 | IConnection 99 | (connect 100 | ([this] 101 | (connect this nil)) 102 | ([this on-connect-fn] 103 | (.connect this on-connect-fn)) 104 | ([this on-connect-fn config-iframe-fn] 105 | (connect this on-connect-fn config-iframe-fn (.-body js/document))) 106 | ([this on-connect-fn config-iframe-fn iframe-parent] 107 | (.createPeerIframe this iframe-parent config-iframe-fn) 108 | (.connect this on-connect-fn))) 109 | 110 | (transmit [this service-name payload] 111 | (.send this (name service-name) payload)) 112 | 113 | (close [this] 114 | (.close this))) 115 | 116 | (defn xpc-connection 117 | "When passed with a config hash-map, returns a parent 118 | CrossPageChannel object. Keys in the config hash map are downcased 119 | versions of the goog.net.xpc.CfgFields enum keys, 120 | e.g. goog.net.xpc.CfgFields.PEER_URI becomes :peer_uri in the config 121 | hash. 122 | 123 | When passed with no args, creates a child CrossPageChannel object, 124 | and the config is automatically taken from the URL param 'xpc', as 125 | per the CrossPageChannel API." 126 | ([] 127 | (when-let [config (.getParameterValue 128 | (Uri. (.-href (.-location js/window))) 129 | "xpc")] 130 | (CrossPageChannel. (gjson/parse config)))) 131 | ([config] 132 | (CrossPageChannel. 133 | (reduce (fn [sum [k v]] 134 | (if-let [field (get xpc-config-fields k)] 135 | (doto sum (aset field v)) 136 | sum)) 137 | (js-obj) 138 | config)))) 139 | 140 | ;; WebSocket is not supported in the 3/23/11 release of Google 141 | ;; Closure, but will be included in the next release. 142 | 143 | #_(defprotocol IWebSocket 144 | (open? [this])) 145 | 146 | #_(extend-type goog.net.WebSocket 147 | 148 | IWebSocket 149 | (open? [this] 150 | (.isOpen this ())) 151 | 152 | IConnection 153 | (connect 154 | ([this url] 155 | (connect this url nil)) 156 | ([this url protocol] 157 | (.open this url protocol))) 158 | 159 | (transmit [this message] 160 | (.send this message)) 161 | 162 | (close [this] 163 | (.close this ())) 164 | 165 | event/EventType 166 | (event-types [this] 167 | (into {} 168 | (map 169 | (fn [[k v]] 170 | [(keyword (. k (toLowerCase))) 171 | v]) 172 | (merge 173 | (js->clj goog.net.WebSocket/EventType)))))) 174 | 175 | #_(defn websocket-connection 176 | ([] 177 | (websocket-connection nil nil)) 178 | ([auto-reconnect?] 179 | (websocket-connection auto-reconnect? nil)) 180 | ([auto-reconnect? next-reconnect-fn] 181 | (goog.net.WebSocket. auto-reconnect? next-reconnect-fn))) 182 | -------------------------------------------------------------------------------- /src/cljs/clojure/browser/repl.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Rich Hickey. All rights reserved. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "Receive - Eval - Print - Loop 10 | 11 | Receive a block of JS (presumably generated by a ClojureScript compiler) 12 | Evaluate it naively 13 | Print the result of evaluation to a string 14 | Send the resulting string back to the server Loop!" 15 | 16 | :author "Bobby Calderwood and Alex Redington"} 17 | clojure.browser.repl 18 | (:require [clojure.browser.net :as net] 19 | [clojure.browser.event :as event])) 20 | 21 | (def xpc-connection (atom nil)) 22 | 23 | (defn repl-print [data] 24 | (if-let [conn @xpc-connection] 25 | (net/transmit conn :print (pr-str data)))) 26 | 27 | (defn evaluate-javascript 28 | "Process a single block of JavaScript received from the server" 29 | [conn block] 30 | (let [result (try {:status :success :value (str (js* "eval(~{block})"))} 31 | (catch :default e 32 | {:status :exception :value (pr-str e) 33 | :stacktrace (if (.hasOwnProperty e "stack") 34 | (.-stack e) 35 | "No stacktrace available.")}))] 36 | (pr-str result))) 37 | 38 | (defn send-result [connection url data] 39 | (net/transmit connection url "POST" data nil 0)) 40 | 41 | (defn send-print 42 | "Send data to be printed in the REPL. If there is an error, try again 43 | up to 10 times." 44 | ([url data] 45 | (send-print url data 0)) 46 | ([url data n] 47 | (let [conn (net/xhr-connection)] 48 | (event/listen conn :error 49 | (fn [_] 50 | (if (< n 10) 51 | (send-print url data (inc n)) 52 | (.log js/console (str "Could not send " data " after " n " attempts."))))) 53 | (net/transmit conn url "POST" data nil 0)))) 54 | 55 | (def order (atom 0)) 56 | 57 | (defn wrap-message [t data] 58 | (pr-str {:type t :content data :order (swap! order inc)})) 59 | 60 | (defn start-evaluator 61 | "Start the REPL server connection." 62 | [url] 63 | (if-let [repl-connection (net/xpc-connection)] 64 | (let [connection (net/xhr-connection)] 65 | (event/listen connection 66 | :success 67 | (fn [e] 68 | (net/transmit 69 | repl-connection 70 | :evaluate-javascript 71 | (.getResponseText (.-currentTarget e) 72 | ())))) 73 | 74 | (net/register-service repl-connection 75 | :send-result 76 | (fn [data] 77 | (send-result connection url (wrap-message :result data)))) 78 | 79 | (net/register-service repl-connection 80 | :print 81 | (fn [data] 82 | (send-print url (wrap-message :print data)))) 83 | 84 | (net/connect repl-connection 85 | (constantly nil)) 86 | 87 | (js/setTimeout #(send-result connection url (wrap-message :ready "ready")) 50)) 88 | (js/alert "No 'xpc' param provided to child iframe."))) 89 | 90 | (defn connect 91 | "Connects to a REPL server from an HTML document. After the 92 | connection is made, the REPL will evaluate forms in the context of 93 | the document that called this function." 94 | [repl-server-url] 95 | (let [repl-connection (net/xpc-connection 96 | {:peer_uri repl-server-url})] 97 | (swap! xpc-connection (constantly repl-connection)) 98 | (net/register-service repl-connection 99 | :evaluate-javascript 100 | (fn [js] 101 | (net/transmit 102 | repl-connection 103 | :send-result 104 | (evaluate-javascript repl-connection js)))) 105 | (net/connect repl-connection 106 | (constantly nil) 107 | (fn [iframe] 108 | (set! (.-display (.-style iframe)) 109 | "none"))))) 110 | -------------------------------------------------------------------------------- /src/cljs/clojure/data.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns 10 | ^{:author "Stuart Halloway", 11 | :doc "Non-core data functions."} 12 | clojure.data 13 | (:require [clojure.set :as set])) 14 | 15 | (declare diff) 16 | 17 | (defn- atom-diff 18 | "Internal helper for diff." 19 | [a b] 20 | (if (= a b) [nil nil a] [a b nil])) 21 | 22 | ;; for big things a sparse vector class would be better 23 | (defn- vectorize 24 | "Convert an associative-by-numeric-index collection into 25 | an equivalent vector, with nil for any missing keys" 26 | [m] 27 | (when (seq m) 28 | (reduce 29 | (fn [result [k v]] (assoc result k v)) 30 | (vec (repeat (apply max (keys m)) nil)) 31 | m))) 32 | 33 | (defn- diff-associative-key 34 | "Diff associative things a and b, comparing only the key k." 35 | [a b k] 36 | (let [va (get a k) 37 | vb (get b k) 38 | [a* b* ab] (diff va vb) 39 | in-a (contains? a k) 40 | in-b (contains? b k) 41 | same (and in-a in-b 42 | (or (not (nil? ab)) 43 | (and (nil? va) (nil? vb))))] 44 | [(when (and in-a (or (not (nil? a*)) (not same))) {k a*}) 45 | (when (and in-b (or (not (nil? b*)) (not same))) {k b*}) 46 | (when same {k ab}) 47 | ])) 48 | 49 | (defn- diff-associative 50 | "Diff associative things a and b, comparing only keys in ks (if supplied)." 51 | ([a b] 52 | (diff-associative a b (set/union (keys a) (keys b)))) 53 | ([a b ks] 54 | (reduce 55 | (fn [diff1 diff2] 56 | (doall (map merge diff1 diff2))) 57 | [nil nil nil] 58 | (map 59 | (partial diff-associative-key a b) 60 | ks)))) 61 | 62 | (defn- diff-sequential 63 | [a b] 64 | (vec (map vectorize (diff-associative 65 | (if (vector? a) a (vec a)) 66 | (if (vector? b) b (vec b)) 67 | (range (max (count a) (count b))))))) 68 | 69 | (defn- diff-set 70 | [a b] 71 | [(not-empty (set/difference a b)) 72 | (not-empty (set/difference b a)) 73 | (not-empty (set/intersection a b))]) 74 | 75 | (defprotocol EqualityPartition 76 | "Implementation detail. Subject to change." 77 | (equality-partition [x] "Implementation detail. Subject to change.")) 78 | 79 | (defprotocol Diff 80 | "Implementation detail. Subject to change." 81 | (diff-similar [a b] "Implementation detail. Subject to change.")) 82 | 83 | (extend-protocol EqualityPartition 84 | nil 85 | (equality-partition [x] :atom) 86 | 87 | string 88 | (equality-partition [x] :atom) 89 | 90 | number 91 | (equality-partition [x] :atom) 92 | 93 | array 94 | (equality-partition [x] :sequential) 95 | 96 | function 97 | (equality-partition [x] :atom) 98 | 99 | boolean 100 | (equality-partition [x] :atom) 101 | 102 | default 103 | (equality-partition [x] 104 | (cond 105 | (satisfies? IMap x) :map 106 | (satisfies? ISet x) :set 107 | (satisfies? ISequential x) :sequential 108 | :default :atom))) 109 | 110 | (extend-protocol Diff 111 | nil 112 | (diff-similar [a b] 113 | (atom-diff a b)) 114 | 115 | string 116 | (diff-similar [a b] 117 | (atom-diff a b)) 118 | 119 | number 120 | (diff-similar [a b] 121 | (atom-diff a b)) 122 | 123 | array 124 | (diff-similar [a b] 125 | (diff-sequential a b)) 126 | 127 | function 128 | (diff-similar [a b] 129 | (atom-diff a b)) 130 | 131 | boolean 132 | (diff-similar [a b] 133 | (atom-diff a b)) 134 | 135 | default 136 | (diff-similar [a b] 137 | ((case (equality-partition a) 138 | :atom atom-diff 139 | :set diff-set 140 | :sequential diff-sequential 141 | :map diff-associative) 142 | a b))) 143 | 144 | (defn diff 145 | "Recursively compares a and b, returning a tuple of 146 | [things-only-in-a things-only-in-b things-in-both]. 147 | Comparison rules: 148 | 149 | * For equal a and b, return [nil nil a]. 150 | * Maps are subdiffed where keys match and values differ. 151 | * Sets are never subdiffed. 152 | * All sequential things are treated as associative collections 153 | by their indexes, with results returned as vectors. 154 | * Everything else (including strings!) is treated as 155 | an atom and compared for equality." 156 | [a b] 157 | (if (= a b) 158 | [nil nil a] 159 | (if (= (equality-partition a) (equality-partition b)) 160 | (diff-similar a b) 161 | (atom-diff a b)))) 162 | 163 | -------------------------------------------------------------------------------- /src/cljs/clojure/reflect.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure.reflect 2 | (:refer-clojure :exclude [meta]) 3 | (:require [clojure.browser.net :as net] 4 | [clojure.browser.event :as event])) 5 | 6 | (defn- evaluate-javascript [block] 7 | (let [result (try (js* "eval(~{block})") 8 | (catch :default e 9 | (.log js/console e)))] 10 | result)) 11 | 12 | (defn- query-reflection 13 | "Issues a GET to /reflect with a single query-parameter string. 14 | Calls cb with the result." 15 | [query-param cb] 16 | (let [conn (net/xhr-connection) 17 | url (str "/reflect?" query-param)] 18 | (event/listen conn :success (fn [e] 19 | (let [resp (.getResponseText (.-currentTarget e) ())] 20 | (cb resp)))) 21 | (event/listen conn :error #(println "Reflection query failed.")) 22 | (net/transmit conn url))) 23 | 24 | (defn meta 25 | "Queries the reflection api with a fully qualified symbol, then calls 26 | callback fn cb with the evaluated cljs map containing that symbol's 27 | meta information." 28 | [sym cb] 29 | (query-reflection (str "var=" (js/encodeURIComponent (str sym))) 30 | #(cb (evaluate-javascript %)))) 31 | 32 | (defn macroexpand 33 | "Queries the reflection api with a quoted macro form, then calls the 34 | callback function with the macroexpanded form, as a string." 35 | [form] 36 | (query-reflection (str "macroform=" (js/encodeURIComponent (str form))) println)) 37 | 38 | (defn print-doc [{:keys [name method-params doc]}] 39 | (when-not (empty? name) 40 | (println name) 41 | (println method-params) 42 | (println doc))) 43 | 44 | (defn doc 45 | "Queries the reflection api with a fully qualified symbol, then prints 46 | documentation information at the repl." 47 | [sym] 48 | (meta sym print-doc)) 49 | -------------------------------------------------------------------------------- /src/cljs/clojure/set.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^{:doc "Set operations such as union/intersection." 10 | :author "Rich Hickey"} 11 | clojure.set) 12 | 13 | (defn- bubble-max-key [k coll] 14 | "Move a maximal element of coll according to fn k (which returns a number) 15 | to the front of coll." 16 | (let [max (apply max-key k coll)] 17 | (cons max (remove #(identical? max %) coll)))) 18 | 19 | (defn union 20 | "Return a set that is the union of the input sets" 21 | ([] #{}) 22 | ([s1] s1) 23 | ([s1 s2] 24 | (if (< (count s1) (count s2)) 25 | (reduce conj s2 s1) 26 | (reduce conj s1 s2))) 27 | ([s1 s2 & sets] 28 | (let [bubbled-sets (bubble-max-key count (conj sets s2 s1))] 29 | (reduce into (first bubbled-sets) (rest bubbled-sets))))) 30 | 31 | (defn intersection 32 | "Return a set that is the intersection of the input sets" 33 | ([s1] s1) 34 | ([s1 s2] 35 | (if (< (count s2) (count s1)) 36 | (recur s2 s1) 37 | (reduce (fn [result item] 38 | (if (contains? s2 item) 39 | result 40 | (disj result item))) 41 | s1 s1))) 42 | ([s1 s2 & sets] 43 | (let [bubbled-sets (bubble-max-key #(- (count %)) (conj sets s2 s1))] 44 | (reduce intersection (first bubbled-sets) (rest bubbled-sets))))) 45 | 46 | (defn difference 47 | "Return a set that is the first set without elements of the remaining sets" 48 | ([s1] s1) 49 | ([s1 s2] 50 | (if (< (count s1) (count s2)) 51 | (reduce (fn [result item] 52 | (if (contains? s2 item) 53 | (disj result item) 54 | result)) 55 | s1 s1) 56 | (reduce disj s1 s2))) 57 | ([s1 s2 & sets] 58 | (reduce difference s1 (conj sets s2)))) 59 | 60 | 61 | (defn select 62 | "Returns a set of the elements for which pred is true" 63 | [pred xset] 64 | (reduce (fn [s k] (if (pred k) s (disj s k))) 65 | xset xset)) 66 | 67 | (defn project 68 | "Returns a rel of the elements of xrel with only the keys in ks" 69 | [xrel ks] 70 | (set (map #(select-keys % ks) xrel))) 71 | 72 | (defn rename-keys 73 | "Returns the map with the keys in kmap renamed to the vals in kmap" 74 | [map kmap] 75 | (reduce 76 | (fn [m [old new]] 77 | (if (contains? map old) 78 | (assoc m new (get map old)) 79 | m)) 80 | (apply dissoc map (keys kmap)) kmap)) 81 | 82 | (defn rename 83 | "Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap" 84 | [xrel kmap] 85 | (set (map #(rename-keys % kmap) xrel))) 86 | 87 | (defn index 88 | "Returns a map of the distinct values of ks in the xrel mapped to a 89 | set of the maps in xrel with the corresponding values of ks." 90 | [xrel ks] 91 | (reduce 92 | (fn [m x] 93 | (let [ik (select-keys x ks)] 94 | (assoc m ik (conj (get m ik #{}) x)))) 95 | {} xrel)) 96 | 97 | (defn map-invert 98 | "Returns the map with the vals mapped to the keys." 99 | [m] (reduce (fn [m [k v]] (assoc m v k)) {} m)) 100 | 101 | (defn join 102 | "When passed 2 rels, returns the rel corresponding to the natural 103 | join. When passed an additional keymap, joins on the corresponding 104 | keys." 105 | ([xrel yrel] ;natural join 106 | (if (and (seq xrel) (seq yrel)) 107 | (let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel)))) 108 | [r s] (if (<= (count xrel) (count yrel)) 109 | [xrel yrel] 110 | [yrel xrel]) 111 | idx (index r ks)] 112 | (reduce (fn [ret x] 113 | (let [found (idx (select-keys x ks))] 114 | (if found 115 | (reduce #(conj %1 (merge %2 x)) ret found) 116 | ret))) 117 | #{} s)) 118 | #{})) 119 | ([xrel yrel km] ;arbitrary key mapping 120 | (let [[r s k] (if (<= (count xrel) (count yrel)) 121 | [xrel yrel (map-invert km)] 122 | [yrel xrel km]) 123 | idx (index r (vals k))] 124 | (reduce (fn [ret x] 125 | (let [found (idx (rename-keys (select-keys x (keys k)) k))] 126 | (if found 127 | (reduce #(conj %1 (merge %2 x)) ret found) 128 | ret))) 129 | #{} s)))) 130 | 131 | (defn subset? 132 | "Is set1 a subset of set2?" 133 | [set1 set2] 134 | (and (<= (count set1) (count set2)) 135 | (every? #(contains? set2 %) set1))) 136 | 137 | (defn superset? 138 | "Is set1 a superset of set2?" 139 | [set1 set2] 140 | (and (>= (count set1) (count set2)) 141 | (every? #(contains? set1 %) set2))) 142 | 143 | (comment 144 | (refer 'set) 145 | (def xs #{{:a 11 :b 1 :c 1 :d 4} 146 | {:a 2 :b 12 :c 2 :d 6} 147 | {:a 3 :b 3 :c 3 :d 8 :f 42}}) 148 | 149 | (def ys #{{:a 11 :b 11 :c 11 :e 5} 150 | {:a 12 :b 11 :c 12 :e 3} 151 | {:a 3 :b 3 :c 3 :e 7 }}) 152 | 153 | (join xs ys) 154 | (join xs (rename ys {:b :yb :c :yc}) {:a :a}) 155 | 156 | (union #{:a :b :c} #{:c :d :e }) 157 | (difference #{:a :b :c} #{:c :d :e}) 158 | (intersection #{:a :b :c} #{:c :d :e}) 159 | 160 | (index ys [:b])) 161 | 162 | -------------------------------------------------------------------------------- /src/cljs/clojure/walk.cljs: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | ;;; walk.cljs - generic tree walker with replacement 10 | 11 | ;; by Stuart Sierra 12 | ;; Jul5 17, 2011 13 | 14 | ;; CHANGE LOG: 15 | ;; 16 | ;; * July 17, 2011: Port to ClojureScript 17 | ;; 18 | ;; * December 15, 2008: replaced 'walk' with 'prewalk' & 'postwalk' 19 | ;; 20 | ;; * December 9, 2008: first version 21 | 22 | 23 | (ns 24 | ^{:author "Stuart Sierra", 25 | :doc "This file defines a generic tree walker for Clojure data 26 | structures. It takes any data structure (list, vector, map, set, 27 | seq), calls a function on every element, and uses the return value 28 | of the function in place of the original. This makes it fairly 29 | easy to write recursive search-and-replace functions, as shown in 30 | the examples. 31 | 32 | Note: \"walk\" supports all Clojure data structures EXCEPT maps 33 | created with sorted-map-by. There is no (obvious) way to retrieve 34 | the sorting function."} 35 | clojure.walk) 36 | 37 | (defn walk 38 | "Traverses form, an arbitrary data structure. inner and outer are 39 | functions. Applies inner to each element of form, building up a 40 | data structure of the same type, then applies outer to the result. 41 | Recognizes all Clojure data structures. Consumes seqs as with doall." 42 | 43 | {:added "1.1"} 44 | [inner outer form] 45 | (cond 46 | (seq? form) (outer (doall (map inner form))) 47 | (coll? form) (outer (into (empty form) (map inner form))) 48 | :else (outer form))) 49 | 50 | (defn postwalk 51 | "Performs a depth-first, post-order traversal of form. Calls f on 52 | each sub-form, uses f's return value in place of the original. 53 | Recognizes all Clojure data structures. Consumes seqs as with doall." 54 | {:added "1.1"} 55 | [f form] 56 | (walk (partial postwalk f) f form)) 57 | 58 | (defn prewalk 59 | "Like postwalk, but does pre-order traversal." 60 | {:added "1.1"} 61 | [f form] 62 | (walk (partial prewalk f) identity (f form))) 63 | 64 | (defn keywordize-keys 65 | "Recursively transforms all map keys from strings to keywords." 66 | {:added "1.1"} 67 | [m] 68 | (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))] 69 | ;; only apply to maps 70 | (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) 71 | 72 | (defn stringify-keys 73 | "Recursively transforms all map keys from keywords to strings." 74 | {:added "1.1"} 75 | [m] 76 | (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))] 77 | ;; only apply to maps 78 | (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) 79 | 80 | (defn prewalk-replace 81 | "Recursively transforms form by replacing keys in smap with their 82 | values. Like clojure/replace but works on any data structure. Does 83 | replacement at the root of the tree first." 84 | {:added "1.1"} 85 | [smap form] 86 | (prewalk (fn [x] (if (contains? smap x) (smap x) x)) form)) 87 | 88 | (defn postwalk-replace 89 | "Recursively transforms form by replacing keys in smap with their 90 | values. Like clojure/replace but works on any data structure. Does 91 | replacement at the leaves of the tree first." 92 | {:added "1.1"} 93 | [smap form] 94 | (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form)) 95 | -------------------------------------------------------------------------------- /test/clj/cljs/build_api_tests.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.build-api-tests 2 | (:use cljs.build.api) 3 | (:use clojure.test) 4 | (:require [cljs.env :as env] 5 | [cljs.analyzer :as ana])) 6 | 7 | (deftest test-target-file-for-cljs-ns 8 | (is (= (.getPath (target-file-for-cljs-ns 'example.core-lib nil)) 9 | "out/example/core_lib.js")) 10 | (is (= (.getPath (target-file-for-cljs-ns 'example.core-lib "output")) 11 | "output/example/core_lib.js"))) 12 | 13 | (deftest test-cljs-dependents-for-macro-namespaces 14 | (env/with-compiler-env (env/default-compiler-env) 15 | (swap! env/*compiler* assoc :cljs.analyzer/namespaces 16 | { 'example.core 17 | {:require-macros {'example.macros 'example.macros 18 | 'mac 'example.macros} 19 | :name 'example.core} 20 | 'example.util 21 | {:require-macros {'example.macros 'example.macros 22 | 'mac 'example.macros} 23 | :name 'example.util} 24 | 'example.helpers 25 | {:require-macros {'example.macros-again 'example.macros-again 26 | 'mac 'example.macros-again} 27 | :name 'example.helpers } 28 | 'example.fun 29 | {:require-macros nil 30 | :name 'example.fun }}) 31 | (is (= (set (cljs-dependents-for-macro-namespaces ['example.macros])) 32 | #{'example.core 'example.util})) 33 | (is (= (set (cljs-dependents-for-macro-namespaces ['example.macros-again])) 34 | #{'example.helpers})) 35 | (is (= (set (cljs-dependents-for-macro-namespaces ['example.macros 'example.macros-again])) 36 | #{'example.core 'example.util 'example.helpers})) 37 | (is (= (set (cljs-dependents-for-macro-namespaces ['example.not-macros])) 38 | #{})))) 39 | 40 | (def test-cenv (atom {})) 41 | (def test-env (assoc-in (ana/empty-env) [:ns :name] 'cljs.user)) 42 | 43 | ;; basic 44 | 45 | (binding [ana/*cljs-ns* 'cljs.user] 46 | (env/with-compiler-env test-cenv 47 | (ana/no-warn 48 | (ana/analyze test-env 49 | '(ns cljs.user 50 | (:use [clojure.string :only [join]])))))) 51 | 52 | ;; linear 53 | 54 | (binding [ana/*cljs-ns* 'cljs.user] 55 | (env/with-compiler-env test-cenv 56 | (ana/no-warn 57 | (ana/analyze test-env 58 | '(ns foo.core))))) 59 | 60 | (binding [ana/*cljs-ns* 'cljs.user] 61 | (env/with-compiler-env test-cenv 62 | (ana/no-warn 63 | (ana/analyze test-env 64 | '(ns bar.core 65 | (:require [foo.core :as foo])))))) 66 | 67 | (binding [ana/*cljs-ns* 'cljs.user] 68 | (env/with-compiler-env test-cenv 69 | (ana/no-warn 70 | (ana/analyze test-env 71 | '(ns baz.core 72 | (:require [bar.core :as bar])))))) 73 | 74 | ;; graph 75 | 76 | (binding [ana/*cljs-ns* 'cljs.user] 77 | (env/with-compiler-env test-cenv 78 | (ana/no-warn 79 | (ana/analyze test-env 80 | '(ns graph.foo.core))))) 81 | 82 | (binding [ana/*cljs-ns* 'cljs.user] 83 | (env/with-compiler-env test-cenv 84 | (ana/no-warn 85 | (ana/analyze test-env 86 | '(ns graph.bar.core 87 | (:require [graph.foo.core :as foo])))))) 88 | 89 | (binding [ana/*cljs-ns* 'cljs.user] 90 | (env/with-compiler-env test-cenv 91 | (ana/no-warn 92 | (ana/analyze test-env 93 | '(ns graph.baz.core 94 | (:require [graph.foo.core :as foo] 95 | [graph.bar.core :as bar])))))) 96 | 97 | (deftest test-cljs-ns-dependencies 98 | (is (= (env/with-compiler-env test-cenv 99 | (cljs-ns-dependents 'clojure.string)) 100 | '(cljs.user))) 101 | (is (= (env/with-compiler-env test-cenv 102 | (cljs-ns-dependents 'foo.core)) 103 | '(bar.core baz.core))) 104 | (is (= (env/with-compiler-env test-cenv 105 | (cljs-ns-dependents 'graph.foo.core)) 106 | '(graph.bar.core graph.baz.core)))) -------------------------------------------------------------------------------- /test/clj/cljs/closure_tests.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.closure-tests 2 | (:refer-clojure :exclude [compile]) 3 | (:use cljs.closure) 4 | (:use clojure.test)) 5 | 6 | (deftest test-make-preamble 7 | (testing "no options" 8 | (is (= "" (make-preamble {})))) 9 | (testing "nodejs" 10 | (testing "with default hashbang" 11 | (is (= "#!/usr/bin/env node\n" (make-preamble {:target :nodejs})))) 12 | (testing "with custom hashbang" 13 | (is (= "#!/bin/env node\n" (make-preamble {:target :nodejs 14 | :hashbang "/bin/env node"})))) 15 | (testing "with no hashbang" 16 | (is (= "" (make-preamble {:target :nodejs 17 | :hashbang false}))) 18 | (testing "and preamble" 19 | (is (= "var preamble1 = require(\"preamble1\");\n" 20 | (make-preamble {:target :nodejs 21 | :hashbang false 22 | :preamble ["cljs/preamble1.js"]}))))) 23 | (testing "with preamble" 24 | (is (= "#!/usr/bin/env node\nvar preamble1 = require(\"preamble1\");\n" 25 | (make-preamble {:target :nodejs 26 | :preamble ["cljs/preamble1.js"]}))))) 27 | (testing "preamble" 28 | (is (= "var preamble1 = require(\"preamble1\");\nvar preamble2 = require(\"preamble2\");\n" 29 | (make-preamble {:preamble ["cljs/preamble1.js" 30 | "cljs/preamble2.js"]}))))) 31 | -------------------------------------------------------------------------------- /test/clj/cljs/compiler_tests.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.compiler-tests 2 | (:use clojure.test) 3 | (:require [cljs.compiler :as c]) 4 | (:require [cljs.env :as e]) 5 | (:require [cljs.util :as util]) 6 | (:import (java.io File))) 7 | 8 | (deftest should-recompile 9 | (let [src (File. "test/hello.cljs") 10 | dst (File/createTempFile "compilertest" ".cljs") 11 | opt {:optimize-constants true} 12 | optmod {:optimize-constants true :elide-asserts false}] 13 | (with-redefs [util/*clojurescript-version* {:major 0 :minor 0 :qualifier 42}] 14 | (e/with-compiler-env (e/default-compiler-env) 15 | (.setLastModified dst (- (.lastModified src) 100)) 16 | (is (c/requires-compilation? src dst opt)) 17 | (c/compile-file src dst opt) 18 | (is (not (c/requires-compilation? src dst opt))) 19 | (is (c/requires-compilation? src dst optmod)) 20 | (c/compile-file src dst optmod) 21 | (is (not (c/requires-compilation? src dst optmod))))))) 22 | 23 | -------------------------------------------------------------------------------- /test/clj/cljs/preamble1.js: -------------------------------------------------------------------------------- 1 | var preamble1 = require("preamble1"); -------------------------------------------------------------------------------- /test/clj/cljs/preamble2.js: -------------------------------------------------------------------------------- 1 | var preamble2 = require("preamble2"); -------------------------------------------------------------------------------- /test/clj/cljs/repl_tests.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.repl-tests 2 | (:require [clojure.java.io :as io] 3 | [cljs.analyzer :as ana] 4 | [cljs.env :as env] 5 | [cljs.repl :as repl] 6 | [cljs.repl.rhino :as rhino]) 7 | (:use clojure.test)) 8 | 9 | #_(deftest file-info 10 | (let [repl-env (rhino/repl-env) 11 | compiler-env (env/default-compiler-env) 12 | repl-env (assoc repl-env ::env/compiler compiler-env)] 13 | (env/with-compiler-env compiler-env 14 | (binding [ana/*cljs-ns* 'cljs.user] 15 | (repl/-setup repl-env))) 16 | (let [assoc-info (get-in @compiler-env [:cljs.analyzer/namespaces 'cljs.core :defs 'assoc]) 17 | {:keys [file line]} assoc-info] 18 | 19 | (is assoc-info) 20 | (is (number? line)) 21 | (is file) 22 | (and file 23 | (is (io/resource file)))))) 24 | -------------------------------------------------------------------------------- /test/cljs/baz.cljs: -------------------------------------------------------------------------------- 1 | (ns baz) 2 | 3 | (defn f [x] x) 4 | -------------------------------------------------------------------------------- /test/cljs/cljs/binding_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.binding-test 2 | (:require [cljs.test :refer-macros [deftest is]] 3 | [cljs.binding-test-other-ns :as o])) 4 | 5 | (deftest test-binding 6 | (is (binding [o/*foo* 2] 7 | (= o/*foo* 2))) 8 | (is (= o/*foo* 1))) 9 | 10 | (deftest test-with-redefs 11 | (is (with-redefs [o/bar 2] 12 | (= o/bar 2))) 13 | (is (= o/bar 10))) 14 | -------------------------------------------------------------------------------- /test/cljs/cljs/binding_test_other_ns.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.binding-test-other-ns) 2 | 3 | (def ^:dynamic *foo* 1) 4 | 5 | (def bar 10) 6 | -------------------------------------------------------------------------------- /test/cljs/cljs/import_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.import-test 2 | (:require [cljs.test :refer-macros [deftest is]]) 3 | (:import goog.math.Long 4 | [goog.math Vec2 Vec3] 5 | [goog.math Integer])) 6 | 7 | (deftest test-import 8 | (is (fn? Long)) 9 | (is (.equals (Long. 4 6) (.add (Long. 1 2) (Long. 3 4)))) 10 | (is (= "12" (str (Long.fromInt 12)))) 11 | (is (not (nil? (Vec2. 1 2)))) 12 | (is (not (nil? (Vec3. 1 2 3)))) 13 | (is (.equals (Integer.fromString "10") (goog.math.Integer.fromString "10")))) 14 | -------------------------------------------------------------------------------- /test/cljs/cljs/keyword_other.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.keyword-other) 2 | 3 | (defn foo [a b] 4 | (+ a b)) 5 | -------------------------------------------------------------------------------- /test/cljs/cljs/keyword_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.keyword-test 2 | (:require-macros [clojure.core :as cc] 3 | [cljs.test :refer [deftest is]]) 4 | (:require [cljs.keyword-other :as other] 5 | [cljs.test])) 6 | 7 | (deftest test-keyword 8 | (is (= ::bar :cljs.keyword-test/bar)) 9 | (is (= ::other/foo :cljs.keyword-other/foo)) 10 | (is (= ::cc/foo :clojure.core/foo))) 11 | -------------------------------------------------------------------------------- /test/cljs/cljs/letfn_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.letfn-test 2 | (:require [cljs.test :refer-macros [deftest is]])) 3 | 4 | (deftest test-letfn 5 | (letfn [(ev? [x] 6 | (if (zero? x) 7 | true 8 | (od? (dec x)))) 9 | (od? [x] 10 | (if (zero? x) 11 | false 12 | (ev? (dec x))))] 13 | (is (ev? 0)) 14 | (is (ev? 10)) 15 | (is (not (ev? 1))) 16 | (is (not (ev? 11))) 17 | (is (not (od? 0))) 18 | (is (not (od? 10))) 19 | (is (od? 1)) 20 | (is (od? 11)))) 21 | -------------------------------------------------------------------------------- /test/cljs/cljs/macro_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.macro-test 2 | (:refer-clojure :exclude [==]) 3 | (:require [cljs.test :refer-macros [deftest is]]) 4 | (:use-macros [cljs.macro-test.macros :only [==]])) 5 | 6 | (deftest test-macros 7 | (is (= (== 1 1) 2))) 8 | -------------------------------------------------------------------------------- /test/cljs/cljs/macro_test/macros.clj: -------------------------------------------------------------------------------- 1 | (ns cljs.macro-test.macros 2 | (:refer-clojure :exclude [==])) 3 | 4 | (defmacro == [a b] 5 | `(+ ~a ~b)) -------------------------------------------------------------------------------- /test/cljs/cljs/ns_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.ns-test 2 | (:refer-clojure :exclude [+ for]) 3 | (:require-macros [clojure.core :as lang] 4 | [cljs.test :refer [deftest is]]) 5 | (:require [cljs.test] 6 | [cljs.ns-test.foo :refer [baz]] 7 | [clojure.set :as s]) 8 | (:use [cljs.ns-test.bar :only [quux]])) 9 | 10 | (def + -) 11 | 12 | (deftest test-ns 13 | (is (= 4 (clojure.core/+ 2 1 1))) 14 | (is (= 0 (cljs.ns-test/+ 2 1 1))) 15 | (is (= 0 (+ 2 1 1))) 16 | (is (= 123 (baz))) 17 | (is (= 123 (quux))) 18 | 19 | (is (= (range 5) (lang/for [x (range 5)] x))) 20 | (is (= #{1 2 3} (s/union #{1} #{2 3})))) 21 | -------------------------------------------------------------------------------- /test/cljs/cljs/ns_test/bar.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.ns-test.bar) 2 | 3 | (defn quux [] 123) 4 | -------------------------------------------------------------------------------- /test/cljs/cljs/ns_test/foo.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.ns-test.foo) 2 | 3 | (defn baz [] 123) 4 | 5 | (def kw ::foo) 6 | (def qkw '::foo) 7 | 8 | (assert (= (str kw) ":cljs.ns-test.foo/foo")) 9 | (assert (= (str qkw) ":cljs.ns-test.foo/foo")) 10 | -------------------------------------------------------------------------------- /test/cljs/cljs/reducers_test.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.reducers-test 2 | (:require [cljs.test :refer-macros [deftest is]] 3 | [clojure.core.reducers :as r])) 4 | 5 | (deftest test-builtin-impls 6 | (is (= 0 (r/fold + nil))) 7 | (is (= [1 2 3 4] (seq (r/reduce r/append! (r/cat) [1 2 3 4])))) 8 | (is (= 10 (r/reduce + (array 1 2 3 4)))) 9 | (is (= 11 (r/reduce + 1 (array 1 2 3 4)))) 10 | (is (= 10 (r/reduce + (list 1 2 3 4)))) 11 | (is (= 11 (r/reduce + 1 (list 1 2 3 4)))) 12 | (is (= (r/fold + + [1 2 3]) 13 | (r/fold + [1 2 3]) 14 | (r/reduce + [1 2 3]) 15 | 6)) 16 | (is (= (r/fold + + (vec (range 2048))) 17 | (r/reduce + (vec (range 2048))))) 18 | (letfn [(f [[ks vs] k v] 19 | [(conj ks k) (conj vs v)]) 20 | (g ([] [#{} #{}]) 21 | ([[ks1 vs1] [ks2 vs2]] 22 | [(into ks1 ks2) (into vs1 vs2)]))] 23 | (is (= (r/reduce f (g) {:a 1 :b 2 :c 3}) 24 | (r/fold g f {:a 1 :b 2 :c 3}) 25 | [#{:a :b :c} #{1 2 3}])) 26 | (let [m (into {} (for [x (range 2048)] [x (- x)]))] 27 | (is (= (r/reduce f (g) m) (r/fold g f m))))) 28 | ;; CLJS-792 29 | (is (= (into [] (r/map identity {})) []))) 30 | -------------------------------------------------------------------------------- /test/cljs/cljs/top_level.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.top-level 2 | (:refer-clojure :exclude [test]) 3 | (:require [cljs.test :refer-macros [deftest is]])) 4 | 5 | (let [foo 1] 6 | (defn bar [] 7 | foo)) 8 | 9 | (let [foo 2] 10 | (defn baz [] 11 | foo)) 12 | 13 | (deftest test 14 | (is (= (bar) 1)) 15 | (is (= (baz) 2))) 16 | -------------------------------------------------------------------------------- /test/cljs/clojure/data_test.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure.data-test 2 | (:require [cljs.test :refer-macros [deftest is]] 3 | [clojure.data :refer [diff]])) 4 | 5 | (deftest test-data 6 | (is (= [nil nil nil] (diff nil nil))) 7 | (is (= [1 2 nil] (diff 1 2))) 8 | (is (= [nil nil [1 2 3]] (diff [1 2 3] '(1 2 3)))) 9 | (is (= [1 [:a :b] nil] (diff 1 [:a :b]))) 10 | (is (= [{:a 1} :b nil] (diff {:a 1} :b))) 11 | (is (= [:team #{:p1 :p2} nil] (diff :team #{:p1 :p2}))) 12 | (is (= [{0 :a} [:a] nil] (diff {0 :a} [:a]))) 13 | (is (= [nil [nil 2] [1]] (diff [1] [1 2]))) 14 | (is (= [nil nil [1 2]] (diff [1 2] (into-array [1 2])))) 15 | (is (= [#{:a} #{:b} #{:c :d}] (diff #{:a :c :d} #{:b :c :d}))) 16 | (is (= [nil nil {:a 1}] (diff {:a 1} {:a 1}))) 17 | (is (= [{:a #{2}} {:a #{4}} {:a #{3}}] (diff {:a #{2 3}} {:a #{3 4}}))) 18 | (is (= [nil nil [1 2]] (diff [1 2] (into-array [1 2])))) 19 | (is (= [nil nil [1 2]] (diff (into-array [1 2]) [1 2]))) 20 | (is (= [{:a {:c [1]}} {:a {:c [0]}} {:a {:c [nil 2] :b 1}}] 21 | (diff {:a {:b 1 :c [1 2]}} {:a {:b 1 :c [0 2]}}))) 22 | (is (= [{:a nil} {:a false} {:b nil :c false}] 23 | (diff {:a nil :b nil :c false} {:a false :b nil :c false})))) 24 | -------------------------------------------------------------------------------- /test/cljs/clojure/string_test.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure.string-test 2 | (:require [cljs.test :as test 3 | :refer-macros [deftest is testing]] 4 | [clojure.string :as s])) 5 | 6 | (deftest test-api 7 | (testing "Testing string reverse" 8 | (is (= "" (s/reverse ""))) 9 | (is (= "tab" (s/reverse "bat"))) 10 | (is (= "c\uD834\uDD1Ea" (s/reverse "a\uD834\uDD1Ec"))) ;; U+1D11E MUSICAL SYMBOL G CLEF 11 | ) 12 | 13 | (testing "Testing string replace" 14 | (is (= "faabar" (s/replace "foobar" \o \a))) 15 | (is (= "barbarbar" (s/replace "foobarfoo" "foo" "bar"))) 16 | (is (= "FOObarFOO" (s/replace "foobarfoo" #"foo" s/upper-case))) 17 | (is (= "barbar)foo" (s/replace "foo(bar)foo" "foo(" "bar")))) 18 | 19 | (testing "Testing string join" 20 | (is (= "" (s/join nil))) 21 | (is (= "" (s/join []))) 22 | (is (= "1" (s/join [1]))) 23 | (is (= "12" (s/join [1 2]))) 24 | (is (= "1,2,3" (s/join \, [1 2 3]))) 25 | (is (= "" (s/join \, []))) 26 | (is (= "1 and-a 2 and-a 3" (s/join " and-a " [1 2 3])))) 27 | 28 | (testing "Testing string capitalize" 29 | (is (= "FOOBAR" (s/upper-case "Foobar"))) 30 | (is (= "foobar" (s/lower-case "FooBar"))) 31 | (is (= "Foobar" (s/capitalize "foobar"))) 32 | (is (= "Foobar" (s/capitalize "FOOBAR")))) 33 | 34 | (testing "Testing string split" 35 | (is (= ["a" "b"] (s/split "a-b" #"-"))) 36 | (is (= ["a" "b" "c"] (s/split "a-b-c" #"-" -1))) 37 | (is (= ["a" "b" "c"] (s/split "a-b-c" #"-" 0))) 38 | (is (= ["a-b-c"] (s/split "a-b-c" #"-" 1))) 39 | (is (= ["a" "b-c"] (s/split "a-b-c" #"-" 2))) 40 | (is (= ["a" "b" "c"] (s/split "a-b-c" #"-" 3))) 41 | (is (= ["a" "b" "c"] (s/split "a-b-c" #"-" 4))) 42 | (is (vector? (s/split "abc" #"-"))) 43 | (is (= ["a-b-c"] (s/split "a-b-c" #"x" 2))) 44 | (is (= ["" "a" "b" "c" ""] (s/split "abc" (re-pattern "") 5))) 45 | (is (= ["a"] (s/split "ab" #"b"))) 46 | (is (= [] (s/split "ab" #"ab")))) 47 | 48 | (testing "Testing string split lines" 49 | (let [result (s/split-lines "one\ntwo\r\nthree")] 50 | (is (= ["one" "two" "three"] result)) 51 | (is (vector? result))) 52 | (is (= (list "foo") (s/split-lines "foo")))) 53 | 54 | (testing "Testing string blank?" 55 | (is (s/blank? nil)) 56 | (is (s/blank? "")) 57 | (is (s/blank? " ")) 58 | (is (s/blank? " \t \n \r ")) 59 | (is (not (s/blank? " foo ")))) 60 | 61 | (testing "Testing string escape" 62 | (is (= "<foo&bar>" 63 | (s/escape "" {\& "&" \< "<" \> ">"}))) 64 | (is (= " \\\"foo\\\" " 65 | (s/escape " \"foo\" " {\" "\\\""}))) 66 | (is (= "faabor" 67 | (s/escape "foobar" {\a \o, \o \a})))) 68 | 69 | (testing "Testing string replace-first" 70 | (is (= "barbarfoo" (s/replace-first "foobarfoo" "foo" "bar"))) 71 | (is (= "barbarfoo" (s/replace-first "foobarfoo" #"foo" "bar"))) 72 | (is (= "z.ology" (s/replace-first "zoology" \o \.))) 73 | (is (= "FOObarfoo" (s/replace-first "foobarfoo" #"foo" s/upper-case)))) 74 | 75 | (testing "Testing string trim" 76 | (is (= "foo " (s/triml " foo "))) 77 | (is (= "" (s/triml " "))) 78 | (is (= " foo" (s/trimr " foo "))) 79 | (is (= "" (s/trimr " "))) 80 | (is (= "foo" (s/trim " foo \r\n")))) 81 | 82 | (testing "Testing string trim-newline" 83 | (is (= "foo" (s/trim-newline "foo\n"))) 84 | (is (= "foo" (s/trim-newline "foo\r\n"))) 85 | (is (= "foo" (s/trim-newline "foo"))) 86 | (is (= "foo\r " (s/trim-newline "foo\r "))) 87 | (is (= "" (s/trim-newline ""))))) 88 | 89 | (comment 90 | 91 | (deftest char-sequence-handling 92 | (are [result f args] (let [[^CharSequence s & more] args] 93 | (= result (apply f (StringBuffer. s) more))) 94 | "paz" s/reverse ["zap"] 95 | "foo:bar" s/replace ["foo-bar" \- \:] 96 | "ABC" s/replace ["abc" #"\w" s/upper-case] 97 | "faa" s/replace ["foo" #"o" (StringBuffer. "a")] 98 | "baz::quux" s/replace-first ["baz--quux" #"--" "::"] 99 | "baz::quux" s/replace-first ["baz--quux" (StringBuffer. "--") (StringBuffer. "::")] 100 | "zim-zam" s/replace-first ["zim zam" #" " (StringBuffer. "-")] 101 | "Pow" s/capitalize ["POW"] 102 | "BOOM" s/upper-case ["boom"] 103 | "whimper" s/lower-case ["whimPER"] 104 | ["foo" "bar"] s/split ["foo-bar" #"-"] 105 | "calvino" s/trim [" calvino "] 106 | "calvino " s/triml [" calvino "] 107 | " calvino" s/trimr [" calvino "] 108 | "the end" s/trim-newline ["the end\r\n\r\r\n"] 109 | true s/blank? [" "] 110 | ["a" "b"] s/split-lines ["a\nb"] 111 | "fa la la" s/escape ["fo lo lo" {\o \a}])) 112 | ) 113 | -------------------------------------------------------------------------------- /test/cljs/foo/ns_shadow_test.cljs: -------------------------------------------------------------------------------- 1 | (ns foo.ns-shadow-test 2 | (:require [cljs.test :refer-macros [deftest is]] 3 | baz)) 4 | 5 | (defn bar [] 1) 6 | 7 | (defn quux [foo] 8 | (+ (foo.ns-shadow-test/bar) foo)) 9 | 10 | (defn id [x] x) 11 | 12 | (defn foo [] (id 42)) 13 | 14 | (defn baz 15 | ([] (baz 2)) 16 | ([x] (quux 2))) 17 | 18 | (deftest test-shadow 19 | (is (= (quux 2) 3)) 20 | (is (= (foo) 42)) 21 | (is (= (baz) 3))) 22 | -------------------------------------------------------------------------------- /test/cljs/test_runner.cljs: -------------------------------------------------------------------------------- 1 | (ns test-runner 2 | (:require [cljs.test :refer-macros [run-tests]] 3 | [cljs.core-test :as core-test] 4 | [cljs.reader-test] 5 | [cljs.binding-test] 6 | [cljs.ns-test] 7 | [clojure.string-test] 8 | [clojure.data-test] 9 | [cljs.macro-test] 10 | [cljs.letfn-test] 11 | [foo.ns-shadow-test] 12 | [cljs.top-level] 13 | [cljs.reducers-test] 14 | [cljs.keyword-test] 15 | [cljs.import-test])) 16 | 17 | (set! *print-newline* false) 18 | (set-print-fn! js/print) 19 | 20 | (run-tests 21 | 'cljs.core-test 22 | 'cljs.reader-test 23 | 'clojure.string-test 24 | 'clojure.data-test 25 | 'cljs.letfn-test 26 | 'cljs.reducers-test 27 | 'cljs.binding-test 28 | 'cljs.macro-test 29 | 'cljs.top-level 30 | 'cljs.keyword-test 31 | 'cljs.ns-test 32 | 'foo.ns-shadow-test 33 | 'cljs.import-test) 34 | -------------------------------------------------------------------------------- /test/hello.cljs: -------------------------------------------------------------------------------- 1 | (ns hello) 2 | (defn ^:export greet [n] 3 | (str "Hello " n)) 4 | --------------------------------------------------------------------------------