├── .gitignore ├── .travis.yml ├── README.md ├── scalajs-plugin-test ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── src │ ├── main │ │ └── scala │ │ │ └── com │ │ │ └── github │ │ │ └── gtache │ │ │ ├── DummyObject.scala │ │ │ └── DummyScalaTag.scala │ └── test │ │ └── scala │ │ └── com │ │ └── github │ │ └── gtache │ │ ├── JUnitFrameworkTest.scala │ │ ├── MiniTestFrameworkTest.scala │ │ ├── NyayaFrameworkTest.scala │ │ ├── ScalaCheckFrameworkTest.scala │ │ ├── ScalaPropsFrameworkTest.scala │ │ ├── ScalaTestFrameworkTest.scala │ │ ├── ScalaTestStateFrameworkTest.scala │ │ └── UTestFrameworkTest.scala └── testjs │ └── testRunWithFile.js └── scalajs-plugin ├── .gitignore ├── build.gradle ├── diff └── 0.6.14- │ └── Scalajsld.scala ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── publish.bat ├── settings.gradle └── src ├── main ├── groovy │ └── com │ │ └── github │ │ └── gtache │ │ ├── ScalajsPlugin.groovy │ │ ├── Utils.groovy │ │ └── tasks │ │ ├── CompileJSTask.groovy │ │ ├── RunJSTask.groovy │ │ ├── ScalajspTask.groovy │ │ └── TestJSTask.groovy ├── resources │ └── META-INF │ │ └── gradle-plugins │ │ └── scalajs-plugin.properties └── scala │ └── com │ └── github │ └── gtache │ ├── Scalajsld.scala │ ├── Scalajsp.scala │ └── testing │ ├── ClassScanner.scala │ ├── FrameworkDetector.scala │ ├── ScalaJSEventHandler.scala │ ├── ScalaJSTestResult.scala │ ├── SimpleLogger.scala │ └── TestFramework.scala └── test ├── groovy └── com │ └── github │ └── gtache │ ├── PluginTest.groovy │ ├── TestUtils.groovy │ └── UtilsTest.groovy ├── java └── com │ └── github │ └── gtache │ └── testing │ └── JavaAnnotation.java └── scala └── com └── github └── gtache └── testing └── ClassScannerTest.scala /.gitignore: -------------------------------------------------------------------------------- 1 | testall.bat -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | jdk: 3 | - oraclejdk8 4 | scala: 5 | - 2.12.1 6 | before_install: 7 | - sudo apt-get -qq update 8 | 9 | script: 10 | - cd ./scalajs-plugin/ 11 | - chmod +x gradlew 12 | - ./gradlew install 13 | - travis_wait 30 ./gradlew build 14 | - cd ../scalajs-plugin-test/ 15 | - chmod +x gradlew 16 | 17 | - ./gradlew RunJS -Pclassname="com.github.gtache.DummyObject" -Pmethname="printSomething(\"blabla\")" -Prhino 18 | - ./gradlew RunJS -Pclassname="com.github.gtache.DummyScalaTag" -Pphantom 19 | - ./gradlew clean 20 | - ./gradlew RunJS -PtoExec="com.github.gtache.DummyScalaTag().main()" -PrunFull -Prhino 21 | - ./gradlew clean 22 | - ./gradlew RunJS -PtoExec="com.github.gtache.DummyObject().main()" -Pclassname="com.github.gtache.DummyScalaTag" -PrunNoOpt 23 | - ./gradlew clean 24 | - ./gradlew RunJS -PfileToExec="testjs/testRunWithFile.js" -PrunFull -Pphantom 25 | - ./gradlew RunJS -PfileToExec="testjs/testRunWithFile.js" -PrunNoOpt -Prhino 26 | - ./gradlew RunJS -PfileToExec="testjs/testRunWithFile.js" 27 | - ./gradlew TestJS 28 | - ./gradlew TestJS -Ptest-only=*JUnit* 29 | - ./gradlew TestJS -Ptest-only=*Scala* -Prhino 30 | - ./gradlew TestJS -Pretest -Pphantom 31 | 32 | 33 | before_cache: 34 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 35 | cache: 36 | directories: 37 | - $HOME/.gradle/caches/ 38 | - $HOME/.gradle/wrapper/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # No more maintained 2 | If you want to take over this project, send me an email. 3 | # scalajs-gradle [![Build Status](https://travis-ci.org/gtache/scalajs-gradle.svg?branch=master)](https://travis-ci.org/gtache/scalajs-gradle) 4 | 5 | ## Requirements 6 | You must `apply plugin: 'scalajs-plugin'` and declare 7 | ``` 8 | buildscript { 9 | repositories { 10 | mavenCentral() 11 | } 12 | dependencies { 13 | classpath 'com.github.gtache:scalajs-plugin:sjs[scalaJSVersion]_[scalaVersion]_0.3.0' 14 | } 15 | } 16 | ``` 17 | to use this plugin. 18 | (With scalaJSVersion '0.6' and scalaVersion '2.12', that would be 'scalajs-plugin:sjs0.6_2.12_0.3.0') 19 | *Check the build.gradle of scalajs-plugin-test if needed.* 20 | Needs .scala files to be in src/main/scala (or [configure your ScalaCompile](https://docs.gradle.org/current/userguide/scala_plugin.html) task accordingly) 21 | Needs tests to be in src/test/scala. 22 | 23 | ## Added by the plugin 24 | This plugin adds : 25 | -`apply plugin: 'java'` 26 | -`apply plugin: 'scala'` 27 | and dependencies on **scalajs-library (version depending on plugin version)**, **scalajs-compiler (version depending on plugin version)**, as well as **org.eclipse.jetty:jetty-server:8.1.16.v20140903** and **org.eclipse.jetty:jetty-websocket:8.1.16.v20140903** for PhantomJS 28 | 29 | ## Usage 30 | `gradlew FastOptJS`, `gradlew FullOptJS` or `gradlew NoOptJS` to compile everything. 31 | 32 | You can run the generated javascript file with `gradlew RunJS`. 33 | You can run tests with `gradlew TestJS`. Be aware that this is still an early feature. 34 | You can read the sjsir files with `gradlew Scalajsp`. 35 | 36 | ## Test frameworks supported 37 | -ScalaTest 38 | -JUnit ***(you have to add the junit-test-plugin to the compileTestScala task)*** 39 | -Minitest 40 | -utest (not fully supported, the summary will print the tests as Unknown and the retest feature will ignore them) 41 | -ScalaProps 42 | You can mix them (Have a JUnit suite with a utest suite and a ScalaTest suite, etc) 43 | You must obviously add the dependencies and TestFrameworks for those to work. 44 | 45 | To add the JUnit plugin or the dependencies, please refer to the *build.gradle* in *scalajs-test-plugin*. 46 | 47 | ### Options for the linker (Fast/Full/NoOptJS) 48 | -`-Po="pathtofile" | -Poutput="pathtofile"` to change where the js file will be generated **This means that there will only be one file for every different build (fast, full, test or not)** 49 | -`-Pp | -Pprettyprint` for prettyPrint 50 | -`-Ps | -Psourcemap` for sourceMap 51 | -`-PcompliantAsInstanceOfs` 52 | -`-Pm=NameOfMode | -PoutputMode=NameOfMode` to change the output mode (ECMAScript51Global, ECMAScript51Isolated, ECMAScript6) 53 | -`-Pc | -PcheckIR` 54 | -`-Pr="PathToSourceMap" | -PrelativizeSourceMap="PathToSourceMap"` to add a sourceMap 55 | -`-PlinkLogLevel=Debug|Info (default)|Warn|Error` to change the level of logging 56 | -`-Pd | -Pdebug` for Debug level 57 | -`-Pq | -Pquiet` for Warn level 58 | -`-Pqq | -Preally-quiet` for Error level 59 | -`-Pbatch` to turn on batch mode 60 | -`-PnoParallel` to set parallel to false 61 | 62 | ### Options for RunJS 63 | -`-Pclassname` is the fully qualified name of the class to run 64 | -`-Pmethname` is the method of classname to run. 65 | -`-PtoExec` (has higher priority than `-Pclassname`) will run the given explicit command 66 | -`-PfileToExec` (has highest priority) will run the given js file. 67 | -Adding `-PrunNoOpt` will run the unoptimized file 68 | -Adding `-PrunFull` will run the fully optimized file 69 | -It will run the fast optimized file by default. 70 | RunJS will depend on FastOptJS (default), FullOptJS or NoOptJS accordingly. 71 | -Adding `-Pphantom` will run the file in a phantomjs environment (needs phantomjs on path). 72 | -Adding `-Prhino` will run the file in a rhino environment. 73 | -Adding `-PjsDom` will run the file with Node.js on a JSDOM window. 74 | -You can change the level of logging with `-PrunLogLevel=Warn` for example. 75 | -You can add java system properties with '-PjavaOpt="-D=;=;..." (replace semicolon with colon if you are on an Unix system) 76 | 77 | Examples : `gradlew RunJS -Pclassname="main.scala.DummyObject"` will compile everything and run DummyObject().main() 78 | 79 | `gradlew RunJS -Pclassname="main.scala.DummyObject" -Pmethname="printSomething(\"blabla\")" -PrunFull` will compile the fully optimized version of the files and will run DummyObject().printSomething("blabla") 80 | 81 | `gradlew RunJS -PtoExec="main.scala.DummyObject().main() -Pphantom"` will compile everything and run DummyObject().main() in a phantomjs environment. 82 | 83 | `gradlew RunJS -PfileToExec="testjs/TestRunWithFile.js"` will run TestRunWithFile.js with the environment loaded with the compiled js file. 84 | 85 | ### Options for TestJS 86 | -`-PrunFull`, `-PrunNoOpt`, `-Pphantom`, `-PjsDom` and `-Prhino` have the same behavior as with RunJS. 87 | -`-Ptest-only=class1;class2;*l*s3` and -`-Ptest-quick=...` should have the same behavior as their sbt counterparts. **You can only select classes / suites at the moment, you can't select tests.** 88 | -`-Pretest` should retest all failed tests (does not work with Utest). 89 | You can change the level of logging with `-PtestLogLevel=Error` for example. 90 | *Note that retest / test-quick need a Gradle daemon to work*. 91 | 92 | ### Options for Scalajsp 93 | -`-Ps` | `-Psupported` will display the supported sjsir versions 94 | -`-Pi` | `-Pinfo` will display informations about the file(s) 95 | -`-Pf` | `-Pfilename` to choose which file(s) to see (eg : 'build/classes/main/com/github/gtache/DummyObject$.sjsir') 96 | -`-Pj` | `-Pjarfile` to choose a jar 97 | 98 | ### Making options 'permanent' 99 | Don't forget that you can set the options directly in build.gradle. Simply put the property in the 'ext' closure. 100 | Example : Instead of writing -PtestLogLevel=Debug -Po="generated.js" -Pd -PfileToExec="toExec/exec.js" everytime, write 101 | 102 | ``` 103 | ext { 104 | testLogLevel="Debug" //Use a string 105 | o="generated.js" 106 | d=true //or false, or whatever, it just checks that the property exists 107 | fileToExec="toExec/exec.js" 108 | testFrameworks=["utest.runner.Framework","minitest.runner.Framework"] //If you need to add TestFrameworks 109 | } 110 | ``` 111 | 112 | ### Possible problems 113 | -*Permission denied* 114 | => Solution : apply chmod +x to gradlew 115 | -*GC overhead limit exceeded* when running CompileJS 116 | => Solution : edit gradle.properties in %USER%/.gradle/ with `org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError` (or tweak the numbers) (source : http://stackoverflow.com/questions/27164452/how-to-solve-java-lang-outofmemoryerror-gc-overhead-limit-exceeded-error-in-and) 117 | (Don't forget to delete the hprof file in the project folder) 118 | -Something related to the linker state, after a failure while linking 119 | => Solution : `gradlew --stop` to stop the daemon containing the linker. Then rerun the desired command as usual. (This problem should be fixed now) 120 | 121 | ## Changelog 122 | ###0.3.0 (uses Scala 2.12.1 or Scala 2.11.8 with scalajs 0.6.15) 123 | -Updates to Scala 2.12 and Scalajs 0.6.15 124 | -Adds Scalajsp 125 | -Adds JSDOMNode environment 126 | -Adds custom environment option 127 | -Adds custom semantics option 128 | -Adds custom OptimizerOptions option 129 | -Adds batchMode, parallel 130 | -Adds Java system properties 131 | -Various improvements / bugfixes 132 | 133 | ###0.2.0 (uses Scala 2.11.8 with scalajs 0.6.9) 134 | -Adds support for RhinoJS and PhantomJS 135 | -Adds options for the linker 136 | -Removes useless tasks 137 | -Adds support for basic testing 138 | -Various improvements (cleaning, bugs, etc) 139 | 140 | ###0.1.1 (uses Scala 2.11.8 with scalajs 0.6.9) 141 | -Adds -PtoExec to input directly what to execute. 142 | -Linker and Cache are kept alive (should increase speed dramatically). Only works with a gradle daemon. 143 | -Fixes a problem with the linker not linking when files are changed. 144 | 145 | ###0.1.0 (uses Scala 2.11.8 with scalajs 0.6.9) 146 | -First version 147 | -------------------------------------------------------------------------------- /scalajs-plugin-test/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | build/ 4 | js/ 5 | sjsir/ 6 | *.iml -------------------------------------------------------------------------------- /scalajs-plugin-test/build.gradle: -------------------------------------------------------------------------------- 1 | import org.scalajs.jsenv.nodejs.* 2 | import com.github.gtache.Scalajsld$ 3 | 4 | group 'com.github.gtache' 5 | version '1.0-SNAPSHOT' 6 | 7 | apply plugin: 'scalajs-plugin' 8 | apply plugin: 'idea' 9 | 10 | sourceCompatibility = 1.8 11 | 12 | buildscript { 13 | String scalaVersion = project.hasProperty('scalaVersion') ? project.property('scalaVersion') : '2.12' 14 | String scalaJSVersion = project.hasProperty('scalaJSVersion') ? project.property('scalaJSVersion') : '0.6.15' 15 | String scalaJSM = scalaJSVersion.substring(0,3) 16 | 17 | String pluginVersion = '0.3.0' 18 | String pluginFullVersion = 'sjs'+scalaJSM+'_'+scalaVersion+'_'+pluginVersion 19 | repositories { 20 | mavenLocal() 21 | mavenCentral() 22 | } 23 | dependencies { 24 | classpath 'com.github.gtache:scalajs-plugin:'+pluginFullVersion 25 | } 26 | } 27 | 28 | configurations { 29 | scalaTestCompile 30 | } 31 | 32 | //Duplication because buildscript{} and the rest of the build file don't share variables 33 | String scalaVersion = project.hasProperty('scalaVersion') ? project.property('scalaVersion') : '2.12' 34 | String subVersion = project.hasProperty('subVersion') ? project.property('subVersion') : '1' 35 | String scalaFullVersion = scalaVersion + '.' + subVersion 36 | String scalaJSVersion = project.hasProperty('scalaJSVersion') ? project.property('scalaJSVersion') : '0.6.15' 37 | String scalaJSM = scalaJSVersion.substring(0,3) 38 | String scalaJSV = scalaJSM+'_'+scalaVersion 39 | 40 | repositories { 41 | mavenCentral() 42 | jcenter() 43 | } 44 | 45 | dependencies { 46 | compile group: 'com.lihaoyi', name: 'scalatags_sjs'+scalaJSV, version: '0.6.3' 47 | testCompile group: 'org.scala-js', name: 'scalajs-junit-test-runtime_'+scalaVersion, version: scalaJSVersion 48 | testCompile group: 'org.scalactic', name: 'scalactic_sjs'+scalaJSV, version: '3.0.1' 49 | testCompile group: 'org.scalatest', name: 'scalatest_sjs'+scalaJSV, version: '3.0.1' 50 | testCompile group: 'org.scalacheck', name: 'scalacheck_sjs'+scalaJSV, version: '1.13.4' 51 | testCompile group: 'com.lihaoyi', name: 'utest_sjs'+scalaJSV, version: '0.4.5' 52 | testCompile group: 'io.monix', name: 'minitest_sjs'+scalaJSV, version: '0.27' 53 | testCompile group: 'com.github.japgolly.nyaya', name: 'nyaya-prop_sjs'+scalaJSV, version: '0.8.1' 54 | testCompile group: 'com.github.japgolly.nyaya', name: 'nyaya-gen_sjs'+scalaJSV, version: '0.8.1' 55 | testCompile group: 'com.github.japgolly.nyaya', name: 'nyaya-test_sjs'+scalaJSV, version: '0.8.1' 56 | testCompile group: 'com.github.scalaprops', name: 'scalaprops_sjs'+scalaJSV, version: '0.4.1' 57 | testCompile group: 'com.github.scalaprops', name: 'scalaprops-scalazlaws_sjs'+scalaJSV, version: '0.4.1' 58 | scalaTestCompile group: 'org.scala-js', name: 'scalajs-junit-test-plugin_'+scalaFullVersion, version: scalaJSVersion 59 | } 60 | 61 | //Necessary to make JUnit work 62 | tasks.findByPath('compileTestScala').doFirst { 63 | scalaCompileOptions.additionalParameters = scalaCompileOptions.additionalParameters + 64 | ["-Xplugin:" + project.configurations.scalaTestCompile.findAll { 65 | it.absolutePath.contains("junit-test-plugin") 66 | }.get(0).absolutePath] 67 | } 68 | 69 | 70 | ext { 71 | testFrameworks = ["utest.runner.Framework"] 72 | testFrameworks += "minitest.runner.Framework" 73 | testFrameworks += "org.scalacheck.ScalaCheckFramework" 74 | testFrameworks += "scalaprops.ScalapropsFramework" 75 | testFrameworks += "scalaprops.ScalapropsFramework" 76 | linkLogLevel = "Debug" 77 | testLogLevel = "Debug" 78 | 79 | //You can configure a custom JSEnv (selenium,...), don't forget to import the classes 80 | //jsEnv = new NodeJSEnv("node", Seq$.MODULE$.empty(), Map$.MODULE$.empty()) 81 | //jsEnv.loadLibs(...) 82 | //jsEnv.withSourceMap(...) 83 | 84 | //You can configure custom Semantics 85 | //semantics = Semantics.Defaults().withProductionMode(true).with... 86 | 87 | //You can configure optimizer options 88 | //oOptions = Scalajsld$.MODULE$.defaultOptions().withParallel(false)... 89 | } 90 | 91 | defaultTasks += 'FastOptJS' 92 | 93 | task wrapper(type: Wrapper) { 94 | gradleVersion = '3.4.1' 95 | } 96 | -------------------------------------------------------------------------------- /scalajs-plugin-test/gradle.properties: -------------------------------------------------------------------------------- 1 | scalaVersion=2.12 2 | subVersion=1 3 | scalaJSVersion=0.6.15 4 | -------------------------------------------------------------------------------- /scalajs-plugin-test/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gtache/scalajs-gradle/914e255eda1f0c86f930bcd90c595a1c3876a9f6/scalajs-plugin-test/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /scalajs-plugin-test/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Mar 26 00:04:46 CET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip 7 | -------------------------------------------------------------------------------- /scalajs-plugin-test/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /scalajs-plugin-test/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /scalajs-plugin-test/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'scalajs-plugin-test' 2 | 3 | -------------------------------------------------------------------------------- /scalajs-plugin-test/src/main/scala/com/github/gtache/DummyObject.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSExport 5 | 6 | @JSExport 7 | object DummyObject extends js.JSApp { 8 | 9 | @JSExport 10 | override def main(): Unit = { 11 | val squared = square(10) 12 | println("Hello ! Square of 10 is " + squared) 13 | } 14 | 15 | /** Computes the square of an integer. 16 | * This demonstrates unit testing. 17 | */ 18 | @JSExport 19 | def square(x: Int): Int = x * x 20 | 21 | @JSExport 22 | def printSomething(s: String): Unit = println(s) 23 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/main/scala/com/github/gtache/DummyScalaTag.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import scala.scalajs.js.annotation.JSExport 4 | import scalatags.Text.all._ 5 | 6 | @JSExport 7 | object DummyScalaTag { 8 | @JSExport 9 | def main(): Unit = { 10 | val page = html( 11 | head( 12 | script(src := "..."), 13 | script( 14 | "alert('Hello World')" 15 | ) 16 | ), 17 | body( 18 | div( 19 | h1(id := "title", "This is a title"), 20 | p("This is a big paragraph of text") 21 | ) 22 | ) 23 | ) 24 | println(page.toString) 25 | } 26 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/JUnitFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import org.junit.Assert._ 4 | import org.junit.Test 5 | 6 | 7 | @Test 8 | class JUnitFrameworkTest { 9 | 10 | @Test 11 | def dummyTest(): Unit = { 12 | assertEquals(100, DummyObject.square(10)) 13 | assertNotEquals(100, DummyObject.square(5)) 14 | } 15 | 16 | @Test 17 | def dummyTest2(): Unit = { 18 | assertEquals(9, DummyObject.square(3)) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/MiniTestFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import minitest._ 4 | 5 | object MiniTestFrameworkTest extends SimpleTestSuite { 6 | test("should be") { 7 | assertEquals(2, 1 + 1) 8 | } 9 | 10 | test("should not be") { 11 | assert(1 + 1 != 3) 12 | } 13 | 14 | test("fail") { 15 | assert(false) 16 | } 17 | 18 | test("should throw") { 19 | class DummyException extends RuntimeException("DUMMY") 20 | def test(): String = throw new DummyException 21 | 22 | intercept[DummyException] { 23 | test() 24 | } 25 | } 26 | 27 | test("test result of") { 28 | assertResult("hello world") { 29 | "hello" + " " + "world" 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/NyayaFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import nyaya.prop._ 4 | import nyaya.test.PropTestOps 5 | 6 | object NyayaFrameworkTest extends PropTestOps { 7 | 8 | val p: Prop[AllThings] = Prop.distinct("thing IDs", (_: AllThings).things.map(_.id)) 9 | 10 | case class Thing(id: Int, name: String) 11 | 12 | case class AllThings(timestamp: Long, things: List[Thing]) 13 | 14 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/ScalaCheckFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import org.scalacheck.Prop.forAll 4 | import org.scalacheck.Properties 5 | 6 | object ScalaCheckFrameworkTest extends Properties("String") { 7 | 8 | property("startsWith") = forAll { (a: String, b: String) => 9 | (a + b).startsWith(a) 10 | } 11 | 12 | property("concatenate") = forAll { (a: String, b: String) => 13 | (a + b).length >= a.length && (a + b).length >= b.length 14 | } 15 | 16 | property("substring") = forAll { (a: String, b: String, c: String) => 17 | (a + b + c).substring(a.length, a.length + b.length) == b 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/ScalaPropsFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import scalaprops.Property.{implies, prop, property} 4 | import scalaprops._ 5 | 6 | object ScalaPropsFrameworkTest extends Scalaprops { 7 | 8 | val makeList = property { n: Int => 9 | implies(n >= 0 && n < 10000, prop(List.fill(n)("").length == n)) 10 | } 11 | 12 | val trivial = property { n: Int => Bool.bool(n == 0).implies(n == 0) } 13 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/ScalaTestFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import org.scalatest._ 4 | 5 | import scala.collection.mutable.Stack 6 | 7 | class ScalaTestFrameworkTestSpec extends FlatSpec with Matchers { 8 | 9 | "A Stack" should "pop values in last-in-first-out order" in { 10 | val stack = new Stack[Int] 11 | stack.push(1) 12 | stack.push(2) 13 | stack.pop() should be(2) 14 | stack.pop() should be(1) 15 | } 16 | 17 | it should "throw NoSuchElementException if an empty stack is popped" in { 18 | val emptyStack = new Stack[Int] 19 | a[NoSuchElementException] should be thrownBy { 20 | emptyStack.pop() 21 | } 22 | } 23 | 24 | assert(true) 25 | } 26 | 27 | class ScalaTestFrameworkTestSuite extends FunSuite { 28 | 29 | test("An empty Set should have size 0") { 30 | assert(Set.empty.isEmpty) 31 | } 32 | 33 | test("Invoking head on an empty Set should produce NoSuchElementException") { 34 | intercept[NoSuchElementException] { 35 | Set.empty.head 36 | } 37 | } 38 | 39 | test("Fail") { 40 | assert(false) 41 | } 42 | } -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/ScalaTestStateFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | class ScalaTestStateFrameworkTest { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /scalajs-plugin-test/src/test/scala/com/github/gtache/UTestFrameworkTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import utest._ 4 | 5 | object UTestFrameworkTest extends TestSuite { 6 | val tests = this { 7 | 'test1 { 8 | assert(true) 9 | } 10 | 'test2 { 11 | 1 == 1 12 | } 13 | 'test3 { 14 | val a = List[Byte](1, 2) 15 | a(1) == 2 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scalajs-plugin-test/testjs/testRunWithFile.js: -------------------------------------------------------------------------------- 1 | com.github.gtache.DummyScalaTag().main() 2 | com.github.gtache.DummyObject().main() 3 | com.github.gtache.DummyObject().printSomething("blabla") -------------------------------------------------------------------------------- /scalajs-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle/ 3 | sjsir/ 4 | js/ 5 | build/ 6 | *.iml -------------------------------------------------------------------------------- /scalajs-plugin/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'de.fuerstenau.buildconfig' version '1.1.8' 3 | } 4 | group 'com.github.gtache' 5 | 6 | 7 | String scalaVersion = project.hasProperty('scalaVersion') ? project.property('scalaVersion') : '2.12' 8 | String subVersion = project.hasProperty('subVersion') ? project.property('subVersion') : '1' 9 | String scalaFullVersion = scalaVersion + '.' + subVersion 10 | String scalaJSVersion = project.hasProperty('scalaJSVersion') ? project.property('scalaJSVersion') : '0.6.15' 11 | String scalaJSM = scalaJSVersion.substring(0,3) 12 | 13 | ext.isReleaseVersion = !version.endsWith("SNAPSHOT") 14 | 15 | 16 | version 'sjs'+scalaJSM+'_'+scalaVersion+'_0.3.0' 17 | 18 | apply plugin: 'idea' 19 | apply plugin: 'scala' 20 | apply plugin: 'groovy' 21 | apply plugin: 'maven' 22 | apply plugin: 'signing' 23 | 24 | sourceCompatibility = 1.8 25 | 26 | buildConfig { 27 | appName = project.name // sets value of NAME field 28 | version = project.version // sets value of VERSION field, 29 | // 'unspecified' if project.version is not set 30 | 31 | clsName = 'BuildConfig' // sets the name of the BuildConfig class 32 | packageName = project.group // sets the package of the BuildConfig class, 33 | // 'de.fuerstenau.buildconfig' if project.group is not set 34 | charset = 'UTF-8' // sets charset of the generated class, 35 | // 'UTF-8' if not set otherwise 36 | buildConfigField 'String', 'SCALA_VERSION', scalaVersion 37 | buildConfigField 'String', 'SUB_VERSION', subVersion 38 | buildConfigField 'String', 'SCALA_FULL_VERSION', scalaFullVersion 39 | buildConfigField 'String', 'SCALAJS_VERSION', scalaJSVersion 40 | buildConfigField 'String', 'PLUGIN_VERSION', project.version.toString() 41 | } 42 | 43 | repositories { 44 | mavenCentral() 45 | } 46 | 47 | dependencies { 48 | compile gradleApi() 49 | compile localGroovy() //Use same version as the one used by Gradle 50 | compile 'org.scala-lang:scala-compiler:' + scalaFullVersion 51 | compile 'org.scala-lang:scala-library:' + scalaFullVersion 52 | compile group: 'org.scala-js', name: 'scalajs-sbt-test-adapter_' + scalaVersion, version: scalaJSVersion 53 | compile group: 'org.scala-js', name: 'scalajs-js-envs_' + scalaVersion, version: scalaJSVersion 54 | compile group: 'org.scala-js', name: 'scalajs-tools_' + scalaVersion, version: scalaJSVersion 55 | testCompile group: 'junit', name: 'junit', version: '4.12' 56 | testCompile group: 'com.google.guava', name: 'guava', version: '21.0' 57 | } 58 | 59 | signing { 60 | required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } 61 | sign configurations.archives 62 | } 63 | 64 | signArchives.onlyIf { project.hasProperty('uploadArchives') } 65 | 66 | task javadocJar(type: Jar) { 67 | classifier = 'javadoc' 68 | from javadoc 69 | } 70 | 71 | task groovydocJar(type: Jar) { 72 | classifier = 'groovydoc' 73 | from groovydoc 74 | } 75 | 76 | task scaladocJar(type: Jar) { 77 | classifier = 'scaladoc' 78 | from scaladoc 79 | } 80 | 81 | task sourcesJar(type: Jar) { 82 | classifier = 'sources' 83 | from sourceSets.main.allSource 84 | } 85 | 86 | artifacts { 87 | archives javadocJar, groovydocJar, scaladocJar, sourcesJar 88 | } 89 | 90 | if (project.hasProperty('upload')) { 91 | uploadArchives { 92 | repositories { 93 | mavenDeployer { 94 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 95 | 96 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { 97 | authentication(userName: ossrhUsername, password: ossrhPassword) 98 | } 99 | 100 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { 101 | authentication(userName: ossrhUsername, password: ossrhPassword) 102 | } 103 | 104 | pom.project { 105 | name 'Scala.JS plugin' 106 | packaging 'jar' 107 | description 'A plugin used to build Scala.js on Gradle.' 108 | url 'https://github.com/gtache/scalajs-gradle' 109 | licenses { 110 | license { 111 | name 'Scala License' 112 | url 'http://www.scala-lang.org/license.html' 113 | } 114 | } 115 | scm { 116 | connection 'scm:git:ssh://git@github.com:gtache/scalajs-gradle.git' 117 | developerConnection 'scm:git:ss://git@github.com:gtache/scalajs-gradle.git' 118 | url 'https://github.com/gtache/scalajs-gradle' 119 | } 120 | 121 | developers { 122 | developer { 123 | id 'gtache' 124 | name 'Guillaume Tâche' 125 | email 'guillaume.tache@hotmail.com' 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | tasks.getByName('compileGroovy').dependsOn('compileScala') 135 | 136 | task wrapper(type: Wrapper) { 137 | gradleVersion = '3.4.1' 138 | } -------------------------------------------------------------------------------- /scalajs-plugin/diff/0.6.14-/Scalajsld.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import java.io.File 4 | import java.net.URI 5 | 6 | import org.scalajs.core.tools.io._ 7 | import org.scalajs.core.tools.linker.Linker 8 | import org.scalajs.core.tools.linker.backend.{LinkerBackend, OutputMode} 9 | import org.scalajs.core.tools.linker.frontend.LinkerFrontend 10 | import org.scalajs.core.tools.logging._ 11 | import org.scalajs.core.tools.sem._ 12 | 13 | /** 14 | * The object used to link and create the js file 15 | * (see https://github.com/scala-js/scala-js/blob/master/cli/src/main/scala/org/scalajs/cli/Scalajsld.scala) 16 | */ 17 | object Scalajsld { 18 | 19 | private var options: Options = Options() 20 | private var optionsChanged: Boolean = false 21 | 22 | //Store linker and cache to gain time 23 | private var linker: Linker = _ 24 | private var cache: IRFileCache#Cache = _ 25 | 26 | /** 27 | * Returns the current options for the linker 28 | * 29 | * @return the options 30 | */ 31 | def getOptions: Options = options 32 | 33 | /** 34 | * Changes the option of the linker 35 | * 36 | * @param newOptions the new options to be set 37 | */ 38 | def setOptions(newOptions: Options): Unit = { 39 | this.options = newOptions 40 | optionsChanged = true 41 | } 42 | 43 | /** 44 | * Returns the default options 45 | * 46 | * @return the default options 47 | */ 48 | def defaultOptions(): Options = { 49 | Options() 50 | } 51 | 52 | /** 53 | * Executes the linker 54 | */ 55 | def exec(): Unit = { 56 | val classpath = options.stdLib.toList ++ options.cp 57 | val irContainers = IRFileCache.IRContainer.fromClasspath(classpath) 58 | val logger = new ScalaConsoleLogger(options.logLevel) 59 | val outFile = WritableFileVirtualJSFile(options.output) 60 | if (optionsChanged || linker == null) { 61 | val semantics: Semantics = 62 | if (options.fullOpt) {options.semantics.optimized} 63 | else {options.semantics} 64 | 65 | val frontendConfig = LinkerFrontend.Config() 66 | .withCheckIR(options.checkIR) 67 | 68 | val backendConfig = LinkerBackend.Config() 69 | .withRelativizeSourceMapBase(options.relativizeSourceMap) 70 | .withPrettyPrint(options.prettyPrint) 71 | 72 | linker = Linker(semantics, options.outputMode, options.sourceMap, 73 | disableOptimizer = options.noOpt, parallel = true, 74 | useClosureCompiler = options.fullOpt, 75 | frontendConfig, backendConfig) 76 | 77 | if (cache == null) { 78 | cache = (new IRFileCache).newCache 79 | } 80 | optionsChanged = false 81 | } 82 | //Reset linker if there is an error (else trying to link with the same one will throw an exception) 83 | try { 84 | linker.link(cache.cached(irContainers), outFile, logger) 85 | } catch { 86 | case e: Exception => linker = null 87 | throw e 88 | } 89 | } 90 | 91 | /** 92 | * A subclass containing the options for the linker 93 | * 94 | * @param cp the classpath 95 | * @param output the output file 96 | * @param jsoutput Deprecated 97 | * @param semantics the semantics to be used 98 | * @param outputMode the output mode 99 | * @param noOpt with no optimization 100 | * @param fullOpt with full optimization 101 | * @param prettyPrint with pretty print 102 | * @param sourceMap if the sourcemap has to be emitted 103 | * @param relativizeSourceMap a sourcemap to use for linking 104 | * @param bypassLinkingErrors bypass errors or not (deprecated) 105 | * @param checkIR checks the sjsir (expensive) 106 | * @param stdLib a library to be used for the linking 107 | * @param logLevel the level of the logging to be displayed 108 | */ 109 | case class Options(cp: Seq[File] = Seq.empty, 110 | output: File = null, 111 | jsoutput: Boolean = false, 112 | semantics: Semantics = Semantics.Defaults, 113 | outputMode: OutputMode = OutputMode.ECMAScript51Isolated, 114 | noOpt: Boolean = false, 115 | fullOpt: Boolean = false, 116 | prettyPrint: Boolean = false, 117 | sourceMap: Boolean = true, 118 | relativizeSourceMap: Option[URI] = None, 119 | bypassLinkingErrors: Boolean = false, 120 | checkIR: Boolean = false, 121 | stdLib: Option[File] = None, 122 | logLevel: Level = Level.Info) { 123 | 124 | def withClasspath(newCp: Seq[File]): Options = { 125 | this.copy(cp = newCp) 126 | } 127 | 128 | def withOutput(newOutput: File): Options = { 129 | this.copy(output = newOutput) 130 | } 131 | 132 | def withJsOutput(newJsOutput: Boolean): Options = { 133 | this.copy(jsoutput = newJsOutput) 134 | } 135 | 136 | def withSemantics(newSemantics: Semantics): Options = { 137 | this.copy(semantics = newSemantics) 138 | } 139 | 140 | def withOutputMode(newOutputMode: OutputMode): Options = { 141 | this.copy(outputMode = newOutputMode) 142 | } 143 | 144 | def withNoOpt(): Options = { 145 | this.copy(fullOpt = false, noOpt = true) 146 | } 147 | 148 | def withFastOpt(): Options = { 149 | this.copy(fullOpt = false, noOpt = false) 150 | } 151 | 152 | def withFullOpt(): Options = { 153 | this.copy(fullOpt = true, noOpt = false) 154 | } 155 | 156 | def withPrettyPrint(newPrettyPrint: Boolean): Options = { 157 | this.copy(prettyPrint = newPrettyPrint) 158 | } 159 | 160 | def withSourceMap(newSourceMap: Boolean): Options = { 161 | this.copy(sourceMap = newSourceMap) 162 | } 163 | 164 | def withRelativizeSourceMap(newRelativizeSourceMap: Option[URI]): Options = { 165 | this.copy(relativizeSourceMap = newRelativizeSourceMap) 166 | } 167 | 168 | def withBypassLinkingErrors(newBypass: Boolean): Options = { 169 | this.copy(bypassLinkingErrors = newBypass) 170 | } 171 | 172 | def withCheckIR(newCheckIR: Boolean): Options = { 173 | this.copy(checkIR = newCheckIR) 174 | } 175 | 176 | def withStdLib(newStdLib: Option[File]): Options = { 177 | this.copy(stdLib = newStdLib) 178 | } 179 | 180 | def withLogLevel(newLogLevel: Level): Options = { 181 | this.copy(logLevel = newLogLevel) 182 | } 183 | 184 | def withCompliantsSemantics(): Options = { 185 | this.copy(semantics = semantics.withAsInstanceOfs(CheckedBehavior.Compliant)) 186 | } 187 | 188 | 189 | override def toString: String = { 190 | "cp : " + cp.foldLeft("")((acc: String, c: File) => acc + "\n" + c.getAbsolutePath) + "\n" + 191 | "output : " + output + " jsoutput : " + jsoutput + "\n" + 192 | "semantics : " + semantics + "\n" + 193 | "outputMode : " + outputMode + "\n" + 194 | "NoOpt : " + noOpt + " ; fullOpt : " + fullOpt + "\n" + 195 | "prettyPrint : " + prettyPrint + "\n" + 196 | "sourcemap : " + sourceMap + "\n" + 197 | "relativizeSourceMap + " + relativizeSourceMap.getOrElse("No sourcemap") + "\n" + 198 | "bypass : " + bypassLinkingErrors + "\n" + 199 | "checkIR : " + checkIR + "\n" + 200 | "stdLib : " + stdLib + "\n" + 201 | "logLevel : " + logLevel 202 | } 203 | 204 | override def equals(that: Any): Boolean = { 205 | that match { 206 | case that: Options => { 207 | this.cp == that.cp && 208 | this.output == that.output && 209 | this.jsoutput == that.jsoutput && 210 | this.semantics == that.semantics && 211 | this.outputMode == that.outputMode && 212 | this.noOpt == that.noOpt && 213 | this.fullOpt == that.fullOpt && 214 | this.prettyPrint == that.prettyPrint && 215 | this.sourceMap == that.sourceMap && 216 | this.relativizeSourceMap == that.relativizeSourceMap && 217 | this.bypassLinkingErrors == that.bypassLinkingErrors && 218 | this.checkIR == that.checkIR && 219 | this.stdLib == that.stdLib && 220 | this.logLevel == that.logLevel 221 | } 222 | case _ => false 223 | } 224 | } 225 | 226 | override def hashCode: Int = { 227 | cp.hashCode + 228 | 2 * output.hashCode + 229 | 3 * jsoutput.hashCode + 230 | 5 * semantics.hashCode + 231 | 7 * outputMode.hashCode + 232 | 11 * noOpt.hashCode + 233 | 13 * fullOpt.hashCode + 234 | 17 * prettyPrint.hashCode + 235 | 19 * sourceMap.hashCode + 236 | 23 * relativizeSourceMap.hashCode + 237 | 29 * bypassLinkingErrors.hashCode + 238 | 31 * checkIR.hashCode + 239 | 37 * stdLib.hashCode + 240 | 41 * logLevel.hashCode 241 | } 242 | 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /scalajs-plugin/gradle.properties: -------------------------------------------------------------------------------- 1 | scalaVersion=2.12 2 | subVersion=1 3 | scalaJSVersion=0.6.15 4 | -------------------------------------------------------------------------------- /scalajs-plugin/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gtache/scalajs-gradle/914e255eda1f0c86f930bcd90c595a1c3876a9f6/scalajs-plugin/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /scalajs-plugin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Mar 06 01:26:35 CET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip 7 | -------------------------------------------------------------------------------- /scalajs-plugin/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /scalajs-plugin/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /scalajs-plugin/publish.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | set "scalaVersion=2.11" 4 | set "subVersion=8" 5 | set "scalaJSVersion=0.6.15" 6 | set "file=gradle.properties" 7 | cd scalajs-plugin 8 | (echo scalaVersion=!scalaVersion! 9 | echo subVersion=!subVersion! 10 | echo scalaJSVersion=!scalaJSVersion!)>%file% 11 | call gradlew.bat uploadArchives -Pupload 12 | set "scalaVersion=2.12" 13 | set "subVersion=1" 14 | (echo scalaVersion=!scalaVersion! 15 | echo subVersion=!subVersion! 16 | echo scalaJSVersion=!scalaJSVersion!)>%file% 17 | call gradlew.bat uploadArchives -Pupload 18 | -------------------------------------------------------------------------------- /scalajs-plugin/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'scalajs-plugin' 2 | 3 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/ScalajsPlugin.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import com.github.gtache.tasks.CompileJSTask 4 | import com.github.gtache.tasks.RunJSTask 5 | import com.github.gtache.tasks.ScalajspTask 6 | import com.github.gtache.tasks.TestJSTask 7 | import org.gradle.api.Plugin 8 | import org.gradle.api.Project 9 | import org.gradle.api.execution.TaskExecutionGraph 10 | import org.gradle.api.tasks.scala.ScalaCompile 11 | 12 | import static com.github.gtache.BuildConfig.* 13 | import static com.github.gtache.Utils.* 14 | import static com.github.gtache.tasks.CompileJSTask.* 15 | import static com.github.gtache.tasks.ScalajspTask.* 16 | 17 | /** 18 | * The main class for the plugin 19 | */ 20 | final class ScalajsPlugin implements Plugin { 21 | 22 | /** 23 | * Applies the plugin to the given project 24 | * @param project The project it will apply the plugin to 25 | */ 26 | @Override 27 | void apply(Project project) { 28 | prepareGraph(project) 29 | warnConflictingProperties(project) 30 | project.logger.info('Applying java plugin') 31 | project.pluginManager.apply('java') 32 | project.logger.info('Applying scala plugin') 33 | project.pluginManager.apply('scala') 34 | project.logger.info('Plugins applied') 35 | 36 | project.configurations { 37 | scalaCompilePlugin 38 | phantomJetty 39 | } 40 | 41 | project.logger.info('Adding scalajs-library and scalajs-compiler dependencies') 42 | project.dependencies.add('compile', 'org.scala-js:scalajs-library_' 43 | + SCALA_VERSION + ':' + SCALAJS_VERSION) 44 | project.dependencies.add('scalaCompilePlugin', 'org.scala-js:scalajs-compiler_' 45 | + SCALA_FULL_VERSION + ':' + SCALAJS_VERSION) 46 | project.logger.info('Adding jetty dependencies') 47 | project.dependencies.add('phantomJetty', 'org.eclipse.jetty:jetty-server:' + JETTY_SERVER_VERSION) 48 | project.dependencies.add('phantomJetty', 'org.eclipse.jetty:jetty-websocket:' + JETTY_WEBSOCKET_VERSION) 49 | project.logger.info('Dependencies added') 50 | 51 | final jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 52 | final jsBaseName = jsDir.absolutePath + File.separator + project.name 53 | final jsFile = project.file(jsBaseName + EXT) 54 | final jsTestFile = project.file(jsBaseName + NOOPT_TEST_SUFFIX) 55 | final jsFastFile = project.file(jsBaseName + FASTOPT_SUFFIX) 56 | final jsTestFastFile = project.file(jsBaseName + FASTOPT_TEST_SUFFIX) 57 | final jsFullFile = project.file(jsBaseName + FULLOPT_SUFFIX) 58 | final jsTestFullFile = project.file(jsBaseName + FULLOPT_TEST_SUFFIX) 59 | 60 | final runNoOpt = project.hasProperty(RUN_NOOPT) 61 | final runFull = project.hasProperty(RUN_FULL) 62 | 63 | 64 | final tasks = project.tasks 65 | 66 | final noOptJS = tasks.create('NoOptJS', CompileJSTask.class) 67 | noOptJS.destFile = jsFile 68 | noOptJS.noOpt() 69 | project.logger.info(noOptJS.name + ' task added') 70 | 71 | final fastOptJS = tasks.create('FastOptJS', CompileJSTask.class) 72 | fastOptJS.destFile = jsFastFile 73 | fastOptJS.fastOpt() 74 | project.logger.info(fastOptJS.name + ' task added') 75 | 76 | final fullOptJS = tasks.create('FullOptJS', CompileJSTask.class) 77 | fullOptJS.destFile = jsFullFile 78 | fullOptJS.fullOpt() 79 | project.logger.info(fullOptJS.name + ' task added') 80 | 81 | final runJS = tasks.create('RunJS', RunJSTask.class) 82 | 83 | final classes = 'classes' 84 | final testClasses = 'testClasses' 85 | 86 | final testJS = tasks.create('TestJS', TestJSTask.class) 87 | testJS.dependsOn(testClasses) 88 | 89 | if (runFull) { 90 | testJS.dependsOn(fullOptJS) 91 | runJS.dependsOn(fullOptJS) 92 | } else if (runNoOpt) { 93 | testJS.dependsOn(noOptJS) 94 | runJS.dependsOn(noOptJS) 95 | } else { 96 | testJS.dependsOn(fastOptJS) 97 | runJS.dependsOn(fastOptJS) 98 | } 99 | project.logger.info(testJS.name + ' task added') 100 | 101 | final scalajsp = tasks.create('Scalajsp', ScalajspTask.class) 102 | project.logger.info(scalajsp.name + ' task added') 103 | 104 | project.afterEvaluate { 105 | tasks.withType(CompileJSTask) { 106 | it.dependsOn(classes) 107 | it.mustRunAfter(testClasses, classes) 108 | it.srcFiles = project.files(project.sourceSets.main.runtimeClasspath) 109 | it.configure() 110 | } 111 | project.gradle.taskGraph.whenReady { TaskExecutionGraph graph -> 112 | if (graph.hasTask(testJS)) { 113 | tasks.withType(CompileJSTask) { 114 | if (it == fastOptJS) { 115 | it.destFile = jsTestFastFile 116 | } else if (it == fullOptJS) { 117 | it.destFile = jsTestFullFile 118 | } else if (it == noOptJS) { 119 | it.destFile = jsTestFile 120 | } else { 121 | throw new IllegalStateException("Unknown task : " + it.name) 122 | } 123 | it.srcFiles = project.files(project.sourceSets.test.runtimeClasspath) 124 | it.configure() 125 | } 126 | } 127 | } 128 | tasks.withType(ScalaCompile) { 129 | scalaCompileOptions.additionalParameters = ["-Xplugin:" + project.configurations.scalaCompilePlugin.findAll { 130 | it.absolutePath.contains('scalajs-compiler') 131 | }.get(0).absolutePath] 132 | } 133 | project.logger.info('Xplugin for compiler added') 134 | project.logger.info('ScalajsPlugin applied') 135 | } 136 | } 137 | 138 | /** 139 | * Warns the user if conflicting parameters are set for the given project 140 | * @param project the project 141 | */ 142 | private static void warnConflictingProperties(Project project) { 143 | Set> linkedProperties = new HashSet<>() 144 | List opt = new ArrayList<>() 145 | List envs = new ArrayList<>() 146 | List output = new ArrayList<>() 147 | List outputMode = new ArrayList<>() 148 | List relSM = new ArrayList<>() 149 | List logLevel = new ArrayList<>() 150 | List filenames = new ArrayList<>() 151 | List jar = new ArrayList<>() 152 | 153 | 154 | opt.add(RUN_FULL) 155 | opt.add(RUN_NOOPT) 156 | envs.add(JSENV) 157 | envs.add(RHINO) 158 | envs.add(PHANTOM) 159 | envs.add(JSDOM) 160 | output.add(MIN_OUTPUT) 161 | output.add(OUTPUT) 162 | outputMode.add(MIN_OUTPUTMODE) 163 | outputMode.add(OUTPUT) 164 | relSM.add(MIN_RELSM) 165 | relSM.add(RELSM) 166 | logLevel.add(MIN_DEBUG) 167 | logLevel.add(DEBUG) 168 | logLevel.add(MIN_WARN) 169 | logLevel.add(WARN) 170 | logLevel.add(MIN_ERR) 171 | logLevel.add(ERR) 172 | logLevel.add(LOG_LEVEL) 173 | filenames.add(MIN_FILENAME) 174 | filenames.add(FILENAME) 175 | jar.add(MIN_JAR) 176 | jar.add(JAR) 177 | 178 | linkedProperties.add(opt) 179 | linkedProperties.add(envs) 180 | linkedProperties.add(output) 181 | linkedProperties.add(outputMode) 182 | linkedProperties.add(relSM) 183 | linkedProperties.add(logLevel) 184 | linkedProperties.add(filenames) 185 | linkedProperties.add(jar) 186 | 187 | for (List l : linkedProperties) { 188 | Set declared = new HashSet<>() 189 | int shortestIndex = -1 190 | for (int i = 0; i < l.size(); ++i) { 191 | if (project.hasProperty(l.get(i))) { 192 | if (shortestIndex < 0) { 193 | shortestIndex = i 194 | } 195 | declared.add(i) 196 | } 197 | } 198 | if (declared.size() > 1) { 199 | String message = declared.collect { x -> l.get(x) }.inject({ acc, word -> acc + ', ' + word }) 200 | message = "Declaring " + message + " ; Assuming " + l.get(shortestIndex) 201 | project.logger.warn(message) 202 | } 203 | } 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/Utils.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import com.github.gtache.testing.TestFramework 4 | import org.gradle.api.Project 5 | import org.gradle.api.execution.TaskExecutionGraph 6 | import org.gradle.api.file.FileCollection 7 | import org.scalajs.core.tools.io.FileVirtualJSFile 8 | import org.scalajs.core.tools.io.MemVirtualJSFile 9 | import org.scalajs.core.tools.jsdep.ResolvedJSDependency 10 | import org.scalajs.core.tools.jsdep.ResolvedJSDependency$ 11 | import org.scalajs.core.tools.linker.backend.ModuleKind 12 | import org.scalajs.core.tools.linker.backend.OutputMode 13 | import org.scalajs.core.tools.logging.Level 14 | import org.scalajs.jsenv.JSEnv 15 | import org.scalajs.jsenv.nodejs.JSDOMNodeJSEnv 16 | import org.scalajs.jsenv.nodejs.NodeJSEnv 17 | import org.scalajs.jsenv.phantomjs.PhantomJSEnv 18 | import org.scalajs.jsenv.phantomjs.PhantomJettyClassLoader 19 | import org.scalajs.jsenv.rhino.RhinoJSEnv 20 | import scala.collection.Map$ 21 | import scala.collection.Seq$ 22 | import scala.collection.immutable.List$ 23 | import scala.collection.mutable.ArrayBuffer 24 | import scala.collection.mutable.ArraySeq 25 | import scala.collection.mutable.Seq 26 | 27 | import java.nio.file.AccessDeniedException 28 | import java.nio.file.Files 29 | 30 | import static com.github.gtache.tasks.CompileJSTask.MIN_OUTPUT 31 | import static com.github.gtache.tasks.CompileJSTask.OUTPUT 32 | import static org.scalajs.core.ir.Utils.escapeJS 33 | 34 | /** 35 | * Helper class for the plugin 36 | */ 37 | public final class Utils { 38 | 39 | public static final String JETTY_SERVER_VERSION = "8.1.16.v20140903" 40 | public static final String JETTY_WEBSOCKET_VERSION = "8.1.16.v20140903" 41 | 42 | public static final String CPSeparator = File.pathSeparator 43 | //All parameters for generated js file 44 | public static final String JS_REL_DIR = File.separator + 'js' + File.separator 45 | public static final String EXT = '.js' 46 | public static final String FULLOPT_SUFFIX = '_fullopt' + EXT 47 | public static final String FASTOPT_SUFFIX = '_fastopt' + EXT 48 | public static final String TEST_SUFFIX = '_test' 49 | public static final String NOOPT_TEST_SUFFIX = TEST_SUFFIX + EXT 50 | public static final String FULLOPT_TEST_SUFFIX = TEST_SUFFIX + FULLOPT_SUFFIX 51 | public static final String FASTOPT_TEST_SUFFIX = TEST_SUFFIX + FASTOPT_SUFFIX 52 | 53 | public static final String RUN_FULL = 'runFull' 54 | public static final String RUN_NOOPT = 'runNoOpt' 55 | 56 | public static final String JAVA_OPT = 'javaOpt' 57 | 58 | //Envs 59 | public static final String RHINO = 'rhino' 60 | public static final String PHANTOM = 'phantom' 61 | public static final String JSENV = 'jsEnv' 62 | public static final String JSDOM = 'jsDom' 63 | 64 | //LogLevel 65 | public static final String ERROR_LVL = 'error' 66 | public static final String WARN_LVL = 'warn' 67 | public static final String INFO_LVL = 'info' 68 | public static final String DEBUG_LVL = 'debug' 69 | 70 | //OutputMode 71 | public static final String ECMA_51_GLOBAL = "ecmascript51global" 72 | public static final String ECMA_51_ISOLATED = "ecmascript51isolated" 73 | public static final String ECMA_6 = "ecmascript6" 74 | 75 | //Module 76 | public static final String COMMONJS_MODULE = "commonJSModule" 77 | public static final String USE_MAIN_MODULE = "useMainModuleInit" 78 | 79 | public static final String TEST_FRAMEWORKS = 'testFrameworks' 80 | 81 | private static TaskExecutionGraph graph 82 | 83 | private Utils() {} 84 | 85 | /** 86 | * Prepares the TaskExecutionGraph for the given project 87 | * @param project 88 | */ 89 | public static void prepareGraph(Project project) { 90 | graph = null //Need to reset, as if we are using a daemon it will be saved 91 | project.gradle.taskGraph.whenReady { graph = it } 92 | } 93 | 94 | /** 95 | * Resolves the level of logging, depending on the project properties 96 | * @param project The project with the property to check 97 | * @param property The property used on the switch 98 | * @return The level of logging (default : Debug) 99 | */ 100 | public static Level resolveLogLevel(Project project, String property, Level base) { 101 | def level = base 102 | if (project.hasProperty(property)) { 103 | switch ((project.property(property) as String).toLowerCase()) { 104 | case ERROR_LVL: 105 | level = Level.Error$.MODULE$ 106 | break 107 | case WARN_LVL: 108 | level = Level.Warn$.MODULE$ 109 | break 110 | case INFO_LVL: 111 | level = Level.Info$.MODULE$ 112 | break 113 | case DEBUG_LVL: 114 | level = Level.Debug$.MODULE$ 115 | break 116 | default: 117 | project.logger.warn("Unknown log level : " + project.property(property)) 118 | break 119 | } 120 | } 121 | return level 122 | } 123 | 124 | /** 125 | * Resolves the environment to use, depending on the project properties 126 | * @param project The project with properties to check 127 | * @return The environment to use (Default : Node) 128 | */ 129 | public static JSEnv resolveEnv(Project project) { 130 | def env 131 | if (project.hasProperty(JSENV)) { 132 | def envObj = project.property(JSENV) 133 | if (envObj instanceof JSEnv) { 134 | env = envObj as JSEnv 135 | } else { 136 | project.logger.error("The object given as \"jsEnv\" is not of type JSEnv") 137 | env = null 138 | } 139 | } else if (project.hasProperty(RHINO)) { 140 | env = new RhinoJSEnv(Scalajsld$.MODULE$.options().semantics(), false) 141 | } else if (project.hasProperty(PHANTOM)) { 142 | final URL[] jars = project.configurations.phantomJetty.findAll { 143 | it.absolutePath.contains('jetty') 144 | }.collect { it.toURI().toURL() } as URL[] 145 | final PhantomJettyClassLoader loader = new PhantomJettyClassLoader(new URLClassLoader(jars), project.buildscript.classLoader) 146 | env = new PhantomJSEnv("phantomjs", List$.MODULE$.empty(), Map$.MODULE$.empty(), true, loader) 147 | } else if (project.hasProperty(JSDOM)) { 148 | env = new JSDOMNodeJSEnv("node", Seq$.MODULE$.empty(), Map$.MODULE$.empty()) 149 | } else { 150 | env = new NodeJSEnv("node", Seq$.MODULE$.empty(), Map$.MODULE$.empty()) 151 | } 152 | return env 153 | } 154 | 155 | /** 156 | * Returns the outputMode corresponding to a string 157 | * @param s The string 158 | * @return the outputMode, or null 159 | */ 160 | public static OutputMode getOutputMode(String s) { 161 | String toCompare = s.toLowerCase() 162 | if (toCompare == ECMA_51_GLOBAL) { 163 | return OutputMode.ECMAScript51Global$.MODULE$ 164 | } else if (toCompare == ECMA_51_ISOLATED) { 165 | return OutputMode.ECMAScript51Isolated$.MODULE$ 166 | } else if (toCompare == ECMA_6) { 167 | return OutputMode.ECMAScript6$.MODULE$ 168 | } else { 169 | return null 170 | } 171 | } 172 | 173 | /** 174 | * Resolves the path of the file to run, depending on full, fast or no optimization 175 | * @return The path of the file 176 | */ 177 | public static String resolvePath(Project project) { 178 | final def buildPath = project.buildDir.absolutePath 179 | final def jsPath = buildPath + JS_REL_DIR 180 | final def baseFilename = jsPath + project.name 181 | if (graph == null) { 182 | project.logger.warn('TaskGraph not ready yet : Possible error when computing output file\n' + 183 | 'Run with TestJS explicitely to be sure it works') 184 | } 185 | //Performs suboptimal check if TaskExecutionGraph not ready 186 | final def hasTest = graph != null ? graph.hasTask(':TestJS') : isTaskInStartParameter(project, 'testjs') 187 | def path 188 | if (project.hasProperty(MIN_OUTPUT)) { 189 | path = project.file(project.property(MIN_OUTPUT)) 190 | } else if (project.hasProperty(OUTPUT)) { 191 | path = project.file(project.property(OUTPUT)) 192 | } else if (project.hasProperty(RUN_FULL)) { 193 | if (hasTest) { 194 | path = project.file(baseFilename + FULLOPT_TEST_SUFFIX).absolutePath 195 | } else { 196 | path = project.file(baseFilename + FULLOPT_SUFFIX).absolutePath 197 | } 198 | } else if (project.hasProperty(RUN_NOOPT)) { 199 | if (hasTest) { 200 | path = project.file(baseFilename + NOOPT_TEST_SUFFIX).absolutePath 201 | } else { 202 | path = project.file(baseFilename + EXT).absolutePath 203 | } 204 | } else { 205 | if (hasTest) { 206 | path = project.file(baseFilename + FASTOPT_TEST_SUFFIX).absolutePath 207 | } else { 208 | path = project.file(baseFilename + FASTOPT_SUFFIX).absolutePath 209 | } 210 | } 211 | return path 212 | } 213 | 214 | /** 215 | * Returns the minimal ResolvedDependency Seq, which is comprised of only the generated js file. 216 | * @param project The project 217 | * @return the (mutable) seq of only one element 218 | */ 219 | public static Seq getMinimalDependencySeq(Project project) { 220 | final FileVirtualJSFile file = new FileVirtualJSFile(project.file(resolvePath(project))) 221 | final ResolvedJSDependency fileD = ResolvedJSDependency.minimal(file) 222 | final ResolvedJSDependency configurations = resolveConfigurationLibs(project) 223 | final Seq dependencySeq = new ArraySeq<>(configurations == null ? 1 : 2) 224 | dependencySeq.update(0, fileD) 225 | if (configurations != null) { 226 | dependencySeq.update(1, configurations) 227 | } 228 | return dependencySeq 229 | } 230 | 231 | /** 232 | * Deletes a file, if it is a folder, deletes it recursively. 233 | * @param file The file to delete 234 | */ 235 | public static void deleteRecursive(File file) { 236 | if (file.exists()) { 237 | if (file.isDirectory()) { 238 | file.listFiles().each { deleteRecursive(it) } 239 | } 240 | try { 241 | if (Files.isWritable(file.toPath())) { 242 | if (!(file.isDirectory() && file.listFiles().size() > 0)) { 243 | Files.deleteIfExists(file.toPath()) 244 | } 245 | } 246 | } 247 | catch (AccessDeniedException e) { 248 | //Files.isWritable doesnt work 100% apparently => can't use project.delete, throws exception sometimes 249 | } 250 | } 251 | } 252 | 253 | /** 254 | * Prints file if it is a file, or all the files contained in file if it is a directory 255 | * @param file The file to print 256 | * @param project For logging (printing) 257 | */ 258 | public static void listRecursive(File file, Project project) { 259 | if (file.isDirectory()) { 260 | file.listFiles().each { 261 | listRecursive(it, project) 262 | } 263 | } else { 264 | project.logger.info(file.name) 265 | } 266 | } 267 | 268 | /** 269 | * Prints all the files in a FileCollection (as well as subfiles if there are directories) 270 | * @param file The FileCollection 271 | * @param project For logging (printing) 272 | */ 273 | public static void listRecursive(FileCollection file, Project project) { 274 | file.files.each { 275 | listRecursive(it, project) 276 | } 277 | } 278 | 279 | /** 280 | * Checks if there is a task to be executed (explicitely specified) 281 | * @param project The project whose startparameters we want to use 282 | * @param task The name task to be checked 283 | */ 284 | public static boolean isTaskInStartParameter(Project project, String task) { 285 | List tasks = project.gradle.startParameter.taskNames.collect { it.toLowerCase() } 286 | return tasks.contains(task.toLowerCase()) 287 | } 288 | 289 | /** 290 | * Returns the list of custom TestFrameworks added by the user 291 | * @param project The project 292 | * @return A list of TestFramework 293 | */ 294 | public static List resolveTestFrameworks(Project project) { 295 | if (project.hasProperty(TEST_FRAMEWORKS)) { 296 | final List frameworksName = (List) project.property(TEST_FRAMEWORKS) 297 | return frameworksName.collect { 298 | final ArrayBuffer seq = new ArrayBuffer<>() 299 | seq.$plus$eq(it) 300 | new TestFramework(seq.toSeq()) 301 | } 302 | } else { 303 | return new ArrayList<>() 304 | } 305 | } 306 | 307 | public static ModuleKind resolveModuleKind(Project project) { 308 | return project.hasProperty(COMMONJS_MODULE) ? ModuleKind.CommonJSModule$.MODULE$ : ModuleKind.NoModule$.MODULE$ 309 | } 310 | 311 | private static Map resolveJavaSystemProperties(Project project) { 312 | if (project.hasProperty(JAVA_OPT)) { 313 | final HashMap options = new HashMap<>() 314 | final javaOpt = project.property(JAVA_OPT) as String 315 | final beginning = javaOpt.substring(0, 2) 316 | if (beginning == '-D') { 317 | final pairs = javaOpt.substring(2, javaOpt.length()).split(CPSeparator) 318 | for (String pair : pairs) { 319 | final keyV = pair.split('=') 320 | if (keyV.length != 2) { 321 | project.logger.error("javaOpt can only be \"-D=" + CPSeparator + "=...\", but received " + project.property(JAVA_OPT)) 322 | throw new IllegalArgumentException() 323 | } else { 324 | options.put(keyV[0], keyV[1]) 325 | } 326 | } 327 | options.each { project.logger.warn(it.getKey() + '->' + it.getValue()) } 328 | return options 329 | } else { 330 | project.logger.error("javaOpt can only be \"-D=" + CPSeparator + "=...\", but received " + project.property(JAVA_OPT)) 331 | throw new IllegalArgumentException() 332 | } 333 | } 334 | return new HashMap() 335 | } 336 | 337 | private static ResolvedJSDependency resolveConfigurationLibs(Project project) { 338 | final javaSystemProperties = resolveJavaSystemProperties(project) 339 | if (javaSystemProperties.isEmpty()) { 340 | return null 341 | } else { 342 | final formattedProps = javaSystemProperties.collect { 343 | "\"" + escapeJS(it.getKey()) + "\": \"" + escapeJS(it.getValue()) + "\"" 344 | } 345 | formattedProps.each { project.logger.warn(it) } 346 | final String code = 347 | "var __ScalaJSEnv = (typeof __ScalaJSEnv === \"object\" && __ScalaJSEnv) ? __ScalaJSEnv : {};\n" + 348 | "__ScalaJSEnv.javaSystemProperties = {" + formattedProps.join(", ") + "};\n" 349 | 350 | return ResolvedJSDependency$.MODULE$.minimal(new MemVirtualJSFile("setJavaSystemProperties.js").withContent(code)) 351 | } 352 | } 353 | 354 | /** 355 | * Takes a wildcard and returns a regex corresponding to it 356 | * Example : com.github.* => com\\.github\\..* 357 | * @param s The string to transform 358 | * @return The regex 359 | */ 360 | public static String toRegex(String s) { 361 | s.collectReplacements { Character c -> 362 | switch (c) { 363 | case '*': 364 | '.*' 365 | break 366 | case '?': 367 | '.' 368 | break 369 | case '.': 370 | case '[': 371 | case ']': 372 | case '(': 373 | case ')': 374 | case '^': 375 | case '$': 376 | case '|': 377 | case '\\': 378 | '\\' + c 379 | break 380 | default: 381 | null 382 | break 383 | } 384 | } 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/tasks/CompileJSTask.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache.tasks 2 | 3 | import com.github.gtache.Scalajsld 4 | import com.github.gtache.Utils 5 | import org.gradle.api.DefaultTask 6 | import org.gradle.api.file.FileCollection 7 | import org.gradle.api.tasks.InputFiles 8 | import org.gradle.api.tasks.OutputFile 9 | import org.gradle.api.tasks.TaskAction 10 | import org.scalajs.core.tools.linker.backend.OutputMode 11 | import org.scalajs.core.tools.logging.Level 12 | import org.scalajs.core.tools.sem.Semantics 13 | import scala.Option 14 | import scala.collection.JavaConverters 15 | 16 | /** 17 | * Task used to compile sjsir and classes file to a js file. 18 | */ 19 | public class CompileJSTask extends DefaultTask { 20 | final String description = "Compiles all sjsir files into a single javascript file" 21 | 22 | //Linker configs 23 | public static final String MIN_OUTPUT = 'o' 24 | public static final String OUTPUT = 'output' 25 | public static final String MIN_PRETTY = 'p' 26 | public static final String PRETTY = 'prettyPrint' 27 | public static final String MIN_N_SOURCEMAP = 'noS' 28 | public static final String N_SOURCEMAP = 'noSourceMap' 29 | public static final String COMPLIANT = 'compliantAsInstanceOfs' 30 | public static final String MIN_OUTPUTMODE = 'm' 31 | public static final String OUTPUTMODE = 'outputMode' 32 | public static final String MIN_CHECKIR = 'c' 33 | public static final String CHECKIR = 'checkIR' 34 | public static final String MIN_RELSM = 'r' 35 | public static final String RELSM = 'relativizeSourceMap' 36 | public static final String LOG_LEVEL = 'linkLogLevel' 37 | public static final String MIN_DEBUG = 'd' 38 | public static final String DEBUG = 'debug' 39 | public static final String MIN_WARN = 'q' 40 | public static final String WARN = 'quiet' 41 | public static final String MIN_ERR = 'qq' 42 | public static final String ERR = 'really-quiet' 43 | public static final String SEMANTICS = 'semantics' 44 | public static final String NO_PARALLEL = 'noParallel' 45 | public static final String BATCH = 'batch' 46 | public static final String OPTIONS = 'oOptions' 47 | 48 | private Scalajsld.Options options 49 | @InputFiles 50 | FileCollection srcFiles 51 | @OutputFile 52 | File destFile 53 | private Boolean fullOpt = false 54 | private Boolean noOpt = false 55 | 56 | /** 57 | * Tells Scalajsld to run with full optimization 58 | */ 59 | def fullOpt() { 60 | this.fullOpt = true 61 | this.noOpt = false 62 | } 63 | 64 | /** 65 | * Tells Scalajsld to run with fast optimization 66 | */ 67 | def fastOpt() { 68 | this.fullOpt = false 69 | this.noOpt = false 70 | } 71 | 72 | /** 73 | * Tells Scalajsld to run with no optimization 74 | */ 75 | def noOpt() { 76 | this.fullOpt = false 77 | this.noOpt = true 78 | } 79 | 80 | /** 81 | * Configure the options given the project properties (given by user) 82 | */ 83 | def configure() { 84 | options = parseOptions() 85 | } 86 | 87 | /** 88 | * Main method of the task, configures and runs Scalajsld 89 | */ 90 | @TaskAction 91 | def run() { 92 | final curOptions = Scalajsld.getOptions() 93 | if (options != curOptions) { 94 | Scalajsld.setOptions(options) 95 | logger.info('Options changed, linker recreated') 96 | } 97 | logger.info('Running linker with ' + options.toString()) 98 | 99 | Scalajsld.exec() 100 | } 101 | 102 | /** 103 | * Returns the options that will be used with the linker 104 | * @return The options 105 | */ 106 | public Scalajsld.Options getOptions() { 107 | return options 108 | } 109 | 110 | /** 111 | * Parse the options given the project properties 112 | * @return The configured options 113 | */ 114 | private Scalajsld.Options parseOptions() { 115 | final cp = project.configurations.runtime + srcFiles 116 | def options = Scalajsld.defaultOptions().withClasspath( 117 | JavaConverters.asScalaSetConverter(cp.getFiles()).asScala().toSet().toSeq()) 118 | 119 | 120 | if (project.hasProperty(OPTIONS)) { 121 | def optimizerOptions = project.property(OPTIONS) 122 | if (optimizerOptions instanceof Scalajsld.Options) { 123 | options = options.withOptimizerOptions(optimizerOptions as Scalajsld.Options) 124 | } else { 125 | project.error("OptimizerOptions are not of the class Scalajsld.Options : was " + project.property(OPTIONS).getClass()) 126 | } 127 | } 128 | if (project.hasProperty(MIN_OUTPUT)) { 129 | destFile = project.file(project.property(MIN_OUTPUT)) 130 | } else if (project.hasProperty(OUTPUT)) { 131 | destFile = project.file(project.property(OUTPUT)) 132 | } 133 | options = options.withOutput(destFile) 134 | 135 | if (fullOpt) { 136 | options = options.withUseClosureCompiler(true) 137 | } else if (noOpt) { 138 | options = options.withDisableOptimizer(true) 139 | } else { 140 | options = options.withDisableOptimizer(false) 141 | } 142 | 143 | if (project.hasProperty(MIN_PRETTY) || project.hasProperty(PRETTY)) { 144 | options = options.withPrettyPrint(true) 145 | } 146 | 147 | if (project.hasProperty(MIN_N_SOURCEMAP) || project.hasProperty(N_SOURCEMAP)) { 148 | options = options.withSourceMap(false) 149 | } 150 | 151 | if (project.hasProperty(COMPLIANT)) { 152 | options = options.withCompliantsSemantics() 153 | } 154 | 155 | if (project.hasProperty(SEMANTICS)) { 156 | def semanticsObj = project.property(SEMANTICS) 157 | if (semanticsObj instanceof Semantics) { 158 | options = options.withSemantics(semanticsObj as Semantics) 159 | } else { 160 | project.logger.error("The object given as \"semantics\" is not of type Semantics : was " + semanticsObj.getClass()) 161 | } 162 | 163 | } else if (fullOpt) { 164 | options = options.withSemantics(options.semantics().withProductionMode(true)) 165 | } 166 | 167 | 168 | if (project.hasProperty(MIN_OUTPUTMODE)) { 169 | String modeS = project.property(MIN_OUTPUTMODE) 170 | OutputMode mode = Utils.getOutputMode(modeS) 171 | if (mode != null) { 172 | options = options.withOutputMode(mode) 173 | } else { 174 | logger.error("Unknown output mode") 175 | } 176 | } else if (project.hasProperty(OUTPUTMODE)) { 177 | String modeS = project.property(OUTPUTMODE) 178 | OutputMode mode = Utils.getOutputMode(modeS) 179 | if (mode != null) { 180 | options = options.withOutputMode(mode) 181 | } else { 182 | logger.error("Unknown output mode") 183 | } 184 | } 185 | 186 | if (project.hasProperty(MIN_CHECKIR) || project.hasProperty(CHECKIR)) { 187 | options = options.withCheckIR(true) 188 | } 189 | 190 | 191 | if (project.hasProperty(MIN_RELSM)) { 192 | options = options.withRelativizeSourceMap(Option.apply(new URI((String) project.property(MIN_RELSM)))) 193 | } else if (project.hasProperty(RELSM)) { 194 | options = options.withRelativizeSourceMap(Option.apply(new URI((String) project.property(RELSM)))) 195 | } 196 | 197 | Level level = Utils.resolveLogLevel(project, LOG_LEVEL, Level.Info$.MODULE$) 198 | if (project.hasProperty(MIN_DEBUG) || project.hasProperty(DEBUG)) { 199 | level = Level.Debug$.MODULE$ 200 | } else if (project.hasProperty(MIN_WARN) || project.hasProperty(WARN)) { 201 | level = Level.Warn$.MODULE$ 202 | } else if (project.hasProperty(MIN_ERR) || project.hasProperty(ERR)) { 203 | level = Level.Error$.MODULE$ 204 | } 205 | if (level != Level.Info$.MODULE$) { 206 | options = options.withLogLevel(level) 207 | } 208 | 209 | if (project.hasProperty(BATCH)) { 210 | options = options.withBatchMode(true) 211 | } 212 | if (project.hasProperty(NO_PARALLEL)) { 213 | options = options.withParallel(false) 214 | } 215 | 216 | 217 | return options 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/tasks/RunJSTask.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache.tasks 2 | 3 | import com.github.gtache.Utils 4 | import org.gradle.api.DefaultTask 5 | import org.gradle.api.tasks.TaskAction 6 | import org.scalajs.core.tools.io.FileVirtualJSFile 7 | import org.scalajs.core.tools.io.MemVirtualJSFile 8 | import org.scalajs.core.tools.io.VirtualJSFile 9 | import org.scalajs.core.tools.logging.Level 10 | import org.scalajs.core.tools.logging.ScalaConsoleLogger 11 | import org.scalajs.jsenv.ConsoleJSConsole$ 12 | import org.scalajs.jsenv.JSEnv 13 | 14 | /** 15 | * Task used to run a js file 16 | */ 17 | public class RunJSTask extends DefaultTask { 18 | final String description = "Runs the generated js file.\n" + 19 | "Needs Node.js / PhantomJS on PATH, or use Rhino.\n" + 20 | "Use -Prhino (highest priority) or -Pphantom. Default : node" 21 | 22 | private static final String LOG_LEVEL = 'runLogLevel' 23 | private static final String EXEC_FILE = 'fileToExec' 24 | private static final String EXEC_CODE = 'toExec' 25 | private static final String CLASSNAME = 'classname' 26 | private static final String METHNAME = 'methname' 27 | 28 | /** 29 | * The main method of the task, resolves the environment and the code to execute, and runs it 30 | */ 31 | @TaskAction 32 | def run() { 33 | final Tuple2 toExec = resolveToExec() 34 | if (toExec.second == null) { 35 | logger.error('Nothing to execute') 36 | } else { 37 | final JSEnv env = Utils.resolveEnv(project) 38 | final Level logLevel = Utils.resolveLogLevel(project, LOG_LEVEL, Level.Debug$.MODULE$) 39 | final dependencySeq = Utils.getMinimalDependencySeq(project) 40 | VirtualJSFile code 41 | if (toExec.first) { 42 | code = new FileVirtualJSFile(project.file(toExec.second)) 43 | } else { 44 | code = new MemVirtualJSFile("userInputCode.js") 45 | code.content_$eq(toExec.second) 46 | } 47 | 48 | 49 | logger.info('Running env ' + env.name() + ' with code ' + code.name() + ' and dependency ' + dependencySeq) 50 | env.jsRunner(dependencySeq, code).run( 51 | new ScalaConsoleLogger(logLevel), 52 | ConsoleJSConsole$.MODULE$) 53 | } 54 | } 55 | 56 | /** 57 | * Resolves the code to execute, depending on the project properties 58 | * @return The code to execute 59 | */ 60 | private Tuple2 resolveToExec() { 61 | def toExec = null 62 | def isFile = false 63 | if (project.hasProperty(EXEC_FILE)) { 64 | toExec = project.property(EXEC_FILE) 65 | isFile = true 66 | } else if (project.hasProperty(EXEC_CODE)) { 67 | toExec = project.property(EXEC_CODE) 68 | } else if (project.hasProperty(CLASSNAME)) { 69 | final classname = project.property(CLASSNAME) 70 | if (!project.hasProperty(METHNAME)) { 71 | toExec = classname + '().main()' 72 | } else { 73 | toExec = classname + '().' + project.property(METHNAME) 74 | } 75 | } 76 | return new Tuple(isFile, toExec) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/tasks/ScalajspTask.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache.tasks 2 | 3 | import com.github.gtache.Scalajsp 4 | import org.gradle.api.DefaultTask 5 | import org.gradle.api.tasks.TaskAction 6 | import scala.Option 7 | import scala.collection.JavaConverters 8 | 9 | import static com.github.gtache.Utils.CPSeparator 10 | 11 | /** 12 | * Task used to call scalajsp 13 | */ 14 | class ScalajspTask extends DefaultTask { 15 | final String description = "Translates and prints sjsir file to a more readable format" 16 | 17 | public static final String MIN_SUPPORTED = 's' 18 | public static final String SUPPORTED = 'supported' 19 | public static final String MIN_INFOS = 'i' 20 | public static final String INFOS = 'info' 21 | public static final String MIN_FILENAME = 'f' 22 | public static final String FILENAME = 'filename' 23 | public static final String MIN_JAR = 'j' 24 | public static final String JAR = 'jarfile' //can't use jar as it is the name of a task apparently... 25 | 26 | /** 27 | * Parametrize the options and calls scalajsp 28 | */ 29 | @TaskAction 30 | def run() { 31 | if (project.hasProperty(MIN_SUPPORTED) || project.hasProperty(SUPPORTED)) { 32 | Scalajsp.printSupported() 33 | } else { 34 | Scalajsp.Options options = Scalajsp.defaultOptions() 35 | if (project.hasProperty(MIN_INFOS) || project.hasProperty(INFOS)) { 36 | options = options.withInfos(true) 37 | } 38 | if (project.hasProperty(MIN_FILENAME)) { 39 | String[] filenames = (project.property(MIN_FILENAME) as String).split(CPSeparator) 40 | options = options.withFileNames(JavaConverters.asScalaSetConverter(filenames.toList().toSet()).asScala() 41 | .toSet().toSeq().toIndexedSeq()) 42 | } else if (project.hasProperty(FILENAME)) { 43 | String[] filenames = (project.property(FILENAME) as String).split(CPSeparator) 44 | options = options.withFileNames(JavaConverters.asScalaSetConverter(filenames.toList().toSet()).asScala() 45 | .toSet().toSeq().toIndexedSeq()) 46 | } 47 | if (project.hasProperty(MIN_JAR)) { 48 | options = options.withJar(Option.apply(project.file(project.property(MIN_JAR)))) 49 | } else if (project.hasProperty(JAR)) { 50 | options = options.withJar(Option.apply(project.file(project.property(JAR)))) 51 | } 52 | Scalajsp.execute(options) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/groovy/com/github/gtache/tasks/TestJSTask.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache.tasks 2 | 3 | import com.github.gtache.Utils 4 | import com.github.gtache.testing.* 5 | import org.gradle.api.DefaultTask 6 | import org.gradle.api.tasks.TaskAction 7 | import org.scalajs.core.tools.jsdep.ResolvedJSDependency 8 | import org.scalajs.core.tools.linker.backend.ModuleKind 9 | import org.scalajs.core.tools.logging.Level 10 | import org.scalajs.core.tools.logging.ScalaConsoleLogger 11 | import org.scalajs.jsenv.ComJSEnv 12 | import org.scalajs.jsenv.ConsoleJSConsole$ 13 | import org.scalajs.testadapter.ScalaJSFramework 14 | import sbt.testing.* 15 | import scala.Option 16 | import scala.collection.JavaConverters 17 | import scala.collection.Seq 18 | import scala.collection.mutable.ArrayBuffer 19 | 20 | import static com.github.gtache.Utils.CPSeparator 21 | 22 | /** 23 | * A task used to run tests for various frameworks 24 | */ 25 | class TestJSTask extends DefaultTask { 26 | final String description = "Runs tests. Depends on a CompileJS task.\n" + 27 | "Can use -PtestLogLevel to change the level of logging, \n" + 28 | "-Ptest-only='...' to test only the given files, \n" + 29 | "-Ptest-quick='...' to test only the given files which have failed during the last testing, \n" + 30 | "-Pretest to run only tests which have failed during the last testing." 31 | 32 | private static final String LOG_LEVEL = 'testLogLevel' 33 | private static final String TEST_ONLY = 'test-only' 34 | private static final String TEST_QUICK = 'test-quick' 35 | private static final String RETEST = 'retest' 36 | 37 | /** 38 | * The action of the task : Instantiates a framework, a runner, and executes all tests found, with the fingerprints 39 | * given by the framework 40 | */ 41 | @TaskAction 42 | def run() { 43 | final Seq dependencySeq = Utils.getMinimalDependencySeq(project) 44 | final libEnv = (ComJSEnv) Utils.resolveEnv(project).loadLibs(dependencySeq) 45 | 46 | final List customTestFrameworks = Utils.resolveTestFrameworks(project) 47 | final ArrayBuffer allFrameworks = new ArrayBuffer<>() 48 | customTestFrameworks.each { 49 | allFrameworks.$plus$eq(it) 50 | } 51 | final Seq defaultFrameworks = TestFrameworks.defaultFrameworks() 52 | for (int i = 0; i < defaultFrameworks.length(); ++i) { 53 | allFrameworks.$plus$eq(defaultFrameworks.apply(i)) 54 | } 55 | final List frameworks = JavaConverters.asJavaIterableConverter(new FrameworkDetector(libEnv, ModuleKind.NoModule$.MODULE$, Option.apply(null)).instantiatedScalaJSFrameworks( 56 | allFrameworks.toSeq(), 57 | new ScalaConsoleLogger(Utils.resolveLogLevel(project, LOG_LEVEL, Level.Info$.MODULE$)), 58 | ConsoleJSConsole$.MODULE$ 59 | )).asJava().toList() 60 | 61 | final URL[] urls = project.sourceSets.test.runtimeClasspath.collect { it.toURI().toURL() } as URL[] 62 | final URLClassLoader classL = new URLClassLoader(urls) 63 | 64 | frameworks.each { ScalaJSFramework framework -> 65 | project.logger.info("Framework found : " + framework.name()) 66 | } 67 | 68 | final String objWildcard = '\\$?' 69 | Set explicitlySpecified = new HashSet<>() 70 | Set excluded = new HashSet() 71 | if (project.hasProperty(TEST_ONLY)) { 72 | explicitlySpecified = ((String) project.property(TEST_ONLY)).split(CPSeparator).toList().toSet() 73 | .collect { Utils.toRegex(it) } 74 | if (explicitlySpecified.isEmpty()) { 75 | explicitlySpecified.add("") 76 | } 77 | } else if (project.hasProperty(TEST_QUICK)) { 78 | explicitlySpecified = ((String) project.property(TEST_QUICK)).split(CPSeparator).toList().toSet() 79 | .collect { Utils.toRegex(it) } 80 | if (explicitlySpecified.isEmpty()) { 81 | explicitlySpecified.add("") 82 | } 83 | excluded = JavaConverters.asJavaCollectionConverter(ScalaJSTestResult$.MODULE$.lastSuccessfulClassnames).asJavaCollection().toSet() 84 | .collect { it + objWildcard } 85 | if (excluded.isEmpty()) { 86 | excluded.add("") 87 | } 88 | } else if (project.hasProperty(RETEST)) { 89 | explicitlySpecified = JavaConverters.asJavaCollectionConverter(ScalaJSTestResult$.MODULE$.lastFailedClassnames).asJavaCollection().toSet() 90 | .collect { it + objWildcard } 91 | if (explicitlySpecified.isEmpty()) { 92 | explicitlySpecified.add("") 93 | } 94 | } 95 | scala.collection.immutable.Set explicitlySpecifiedScala = JavaConverters.asScalaSetConverter(explicitlySpecified).asScala().toSet() 96 | scala.collection.immutable.Set excludedScala = JavaConverters.asScalaSetConverter(excluded).asScala().toSet() 97 | 98 | Logger[] simpleLoggerArray = new SimpleLogger() as Logger[] 99 | frameworks.each { ScalaJSFramework framework -> 100 | final Runner runner = framework.runner(new String[0], new String[0], null) 101 | final Fingerprint[] fingerprints = framework.fingerprints() 102 | final Task[] tasks = runner.tasks(ClassScanner.scan(classL, fingerprints, explicitlySpecifiedScala, excludedScala)) 103 | project.logger.info("Executing " + framework.name()) 104 | if (tasks.length == 0) { 105 | project.logger.info("No tasks found") 106 | } else { 107 | final ScalaJSTestStatus testStatus = new ScalaJSTestStatus(framework) 108 | final EventHandler eventHandler = new ScalaJSEventHandler(testStatus) 109 | ScalaJSTestResult$.MODULE$.statuses_$eq(ScalaJSTestResult.statuses().$plus(testStatus) as scala.collection.immutable.Set) 110 | tasks.each { Task t -> 111 | t.execute(eventHandler, simpleLoggerArray) 112 | } 113 | project.logger.lifecycle('\n') 114 | runner.done() 115 | testStatus.finished_$eq(true) 116 | } 117 | } 118 | 119 | project.logger.lifecycle(ScalaJSTestResult.toString()) 120 | boolean success = ScalaJSTestResult.isSuccess() 121 | ScalaJSTestResult.save() 122 | 123 | //Make build fail 124 | if (!success) { 125 | throw new Exception("There were failures while testing") 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/resources/META-INF/gradle-plugins/scalajs-plugin.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.github.gtache.ScalajsPlugin -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/Scalajsld.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import java.io.File 4 | import java.net.URI 5 | 6 | import org.scalajs.core.tools.io._ 7 | import org.scalajs.core.tools.linker.backend.{LinkerBackend, ModuleKind, OutputMode} 8 | import org.scalajs.core.tools.linker.frontend.LinkerFrontend 9 | import org.scalajs.core.tools.linker.{ClearableLinker, Linker, ModuleInitializer} 10 | import org.scalajs.core.tools.logging._ 11 | import org.scalajs.core.tools.sem._ 12 | 13 | /** 14 | * The object used to link and create the js file 15 | * (see https://github.com/scala-js/scala-js/blob/master/cli/src/main/scala/org/scalajs/cli/Scalajsld.scala) 16 | */ 17 | object Scalajsld { 18 | 19 | private var options: Options = Options() 20 | private var optionsChanged: Boolean = false 21 | 22 | //Store linker and cache to gain time 23 | private var linker: ClearableLinker = _ 24 | private var cache: IRFileCache#Cache = _ 25 | 26 | /** 27 | * Returns the current options for the linker 28 | * 29 | * @return the options 30 | */ 31 | def getOptions: Options = options 32 | 33 | /** 34 | * Changes the option of the linker 35 | * 36 | * @param newOptions the new options to be set 37 | */ 38 | def setOptions(newOptions: Options): Unit = { 39 | this.options = newOptions 40 | optionsChanged = true 41 | } 42 | 43 | /** 44 | * Returns the default options 45 | * 46 | * @return the default options 47 | */ 48 | def defaultOptions(): Options = { 49 | Options() 50 | } 51 | 52 | /** 53 | * Executes the linker 54 | */ 55 | def exec(): Unit = { 56 | val classpath = options.stdLib.toList ++ options.cp 57 | val irContainers = IRFileCache.IRContainer.fromClasspath(classpath) 58 | val logger = new ScalaConsoleLogger(options.logLevel) 59 | val outFile = WritableFileVirtualJSFile(options.output) 60 | if (optionsChanged || linker == null) { 61 | val semantics: Semantics = 62 | if (options.fullOpt) { 63 | options.semantics.optimized 64 | } 65 | else { 66 | options.semantics 67 | } 68 | 69 | val frontendConfig = LinkerFrontend.Config() 70 | .withCheckIR(options.checkIR) 71 | 72 | val backendConfig = LinkerBackend.Config() 73 | .withRelativizeSourceMapBase(options.relativizeSourceMap) 74 | .withPrettyPrint(options.prettyPrint) 75 | 76 | 77 | val config = Linker.Config() 78 | .withBackendConfig(backendConfig) 79 | .withFrontendConfig(frontendConfig) 80 | .withClosureCompilerIfAvailable(options.fullOpt) 81 | .withOptimizer(!options.noOpt) 82 | .withParallel(options.parallel) 83 | .withSourceMap(options.sourceMap) 84 | linker = new ClearableLinker(() => Linker(semantics, options.outputMode, options.moduleKind, 85 | config), options.batchMode) 86 | if (cache == null) { 87 | cache = (new IRFileCache).newCache 88 | } 89 | try { 90 | linker.link(cache.cached(irContainers), options.moduleInitializers, outFile, logger) 91 | } catch { 92 | case e: Exception => linker = null 93 | throw e 94 | } 95 | } 96 | 97 | optionsChanged = false 98 | 99 | 100 | } 101 | 102 | /** 103 | * A subclass containing the options for the linker 104 | * 105 | * @param cp the classpath 106 | * @param moduleInitializers the initializers 107 | * @param output the output file 108 | * @param jsoutput Deprecated 109 | * @param semantics the semantics to be used 110 | * @param outputMode the output mode 111 | * @param moduleKind the type of the modules 112 | * @param noOpt with no optimization 113 | * @param fullOpt with full optimization 114 | * @param prettyPrint with pretty print 115 | * @param sourceMap if the sourcemap has to be emitted 116 | * @param relativizeSourceMap a sourcemap to use for linking 117 | * @param bypassLinkingErrors bypass errors or not (deprecated) 118 | * @param checkIR checks the sjsir (expensive) 119 | * @param stdLib a library to be used for the linking 120 | * @param logLevel the level of the logging to be displayed 121 | */ 122 | 123 | case class Options(cp: Seq[File] = Seq.empty, 124 | moduleInitializers: Seq[ModuleInitializer] = Seq.empty, 125 | output: File = null, 126 | jsoutput: Boolean = false, 127 | semantics: Semantics = Semantics.Defaults, 128 | outputMode: OutputMode = OutputMode.ECMAScript51Isolated, 129 | moduleKind: ModuleKind = ModuleKind.NoModule, 130 | noOpt: Boolean = false, 131 | fullOpt: Boolean = false, 132 | prettyPrint: Boolean = false, 133 | sourceMap: Boolean = false, 134 | relativizeSourceMap: Option[URI] = None, 135 | bypassLinkingErrors: Boolean = false, 136 | batchMode: Boolean = false, 137 | parallel: Boolean = true, 138 | checkIR: Boolean = false, 139 | stdLib: Option[File] = None, 140 | logLevel: Level = Level.Info) { 141 | 142 | def withClasspath(newCp: Seq[File]): Options = { 143 | this.copy(cp = newCp) 144 | } 145 | 146 | def withModuleInitializers(newModuleIntializers: Seq[ModuleInitializer]): Options = { 147 | this.copy(moduleInitializers = newModuleIntializers) 148 | } 149 | 150 | def withOutput(newOutput: File): Options = { 151 | this.copy(output = newOutput) 152 | } 153 | 154 | def withJsOutput(newJsOutput: Boolean): Options = { 155 | this.copy(jsoutput = newJsOutput) 156 | } 157 | 158 | def withSemantics(newSemantics: Semantics): Options = { 159 | this.copy(semantics = newSemantics) 160 | } 161 | 162 | def withOutputMode(newOutputMode: OutputMode): Options = { 163 | this.copy(outputMode = newOutputMode) 164 | } 165 | 166 | def withModuleKind(newModuleKind: ModuleKind): Options = { 167 | this.copy(moduleKind = newModuleKind) 168 | } 169 | 170 | def withSourceMap(newSourceMap: Boolean): Options = { 171 | this.copy(sourceMap = newSourceMap) 172 | } 173 | 174 | def withRelativizeSourceMap(newRelativizeSourceMap: Option[URI]): Options = { 175 | this.copy(relativizeSourceMap = newRelativizeSourceMap) 176 | } 177 | 178 | def withStdLib(newStdLib: Option[File]): Options = { 179 | this.copy(stdLib = newStdLib) 180 | } 181 | 182 | def withLogLevel(newLogLevel: Level): Options = { 183 | this.copy(logLevel = newLogLevel) 184 | } 185 | 186 | def withCompliantsSemantics(): Options = { 187 | this.copy(semantics = semantics.withAsInstanceOfs(CheckedBehavior.Compliant)) 188 | } 189 | 190 | def withOptimizerOptions(newOptions: Options): Options = { 191 | this.withBypassLinkingErrors(newOptions.bypassLinkingErrors) 192 | .withParallel(newOptions.parallel) 193 | .withBatchMode(newOptions.batchMode) 194 | .withDisableOptimizer(!newOptions.noOpt) 195 | .withPrettyPrint(newOptions.prettyPrint) 196 | .withCheckIR(newOptions.checkIR) 197 | .withUseClosureCompiler(newOptions.fullOpt) 198 | } 199 | 200 | def withDisableOptimizer(newFastOpt: Boolean): Options = { 201 | this.copy(noOpt = !newFastOpt) 202 | } 203 | 204 | def withUseClosureCompiler(newFullOpt: Boolean): Options = { 205 | this.copy(fullOpt = newFullOpt) 206 | } 207 | 208 | def withPrettyPrint(newPrettyPrint: Boolean): Options = { 209 | this.copy(prettyPrint = newPrettyPrint) 210 | } 211 | 212 | def withBypassLinkingErrors(newBypass: Boolean): Options = { 213 | this.copy(bypassLinkingErrors = newBypass) 214 | } 215 | 216 | def withCheckIR(newCheckIR: Boolean): Options = { 217 | this.copy(checkIR = newCheckIR) 218 | } 219 | 220 | def withBatchMode(newBatchMode: Boolean): Options = { 221 | this.copy(batchMode = newBatchMode) 222 | } 223 | 224 | def withParallel(newParallel: Boolean): Options = { 225 | this.copy(parallel = newParallel) 226 | } 227 | 228 | override def toString: String = { 229 | "cp : " + cp.foldLeft("")((acc: String, c: File) => acc + "\n" + c.getAbsolutePath) + "\n" + 230 | "moduleInitializers : " + moduleInitializers.mkString(", ") + "\n" + 231 | "output : " + output + " jsoutput : " + jsoutput + "\n" + 232 | "semantics : " + semantics + "\n" + 233 | "outputMode : " + outputMode + "\n" + 234 | "moduleKind : " + moduleKind + "\n" + 235 | "NoOpt : " + noOpt + " ; fullOpt : " + fullOpt + "\n" + 236 | "prettyPrint : " + prettyPrint + "\n" + 237 | "sourcemap : " + sourceMap + "\n" + 238 | "relativizeSourceMap + " + relativizeSourceMap.getOrElse("No sourcemap") + "\n" + 239 | "bypass : " + bypassLinkingErrors + "\n" + 240 | "parallel : " + parallel + "\n" + 241 | "batch mode : " + batchMode + "\n" + 242 | "checkIR : " + checkIR + "\n" + 243 | "stdLib : " + stdLib + "\n" + 244 | "logLevel : " + logLevel 245 | } 246 | 247 | override def equals(that: Any): Boolean = { 248 | that match { 249 | case that: Options => 250 | this.cp == that.cp && 251 | this.moduleInitializers == that.moduleInitializers && 252 | this.output == that.output && 253 | this.jsoutput == that.jsoutput && 254 | this.semantics == that.semantics && 255 | this.outputMode == that.outputMode && 256 | this.moduleKind == that.moduleKind && 257 | this.noOpt == that.noOpt && 258 | this.fullOpt == that.fullOpt && 259 | this.prettyPrint == that.prettyPrint && 260 | this.sourceMap == that.sourceMap && 261 | this.relativizeSourceMap == that.relativizeSourceMap && 262 | this.bypassLinkingErrors == that.bypassLinkingErrors && 263 | this.parallel == that.parallel && 264 | this.batchMode == that.batchMode && 265 | this.checkIR == that.checkIR && 266 | this.stdLib == that.stdLib && 267 | this.logLevel == that.logLevel 268 | case _ => false 269 | } 270 | } 271 | 272 | override def hashCode: Int = { 273 | cp.hashCode + 274 | 47 * moduleInitializers.hashCode + 275 | 2 * output.hashCode + 276 | 3 * jsoutput.hashCode + 277 | 5 * semantics.hashCode + 278 | 7 * outputMode.hashCode + 279 | 71 * moduleKind.hashCode + 280 | 11 * noOpt.hashCode + 281 | 13 * fullOpt.hashCode + 282 | 17 * prettyPrint.hashCode + 283 | 19 * sourceMap.hashCode + 284 | 23 * relativizeSourceMap.hashCode + 285 | 29 * bypassLinkingErrors.hashCode + 286 | 97 * parallel.hashCode() + 287 | 101 * batchMode.hashCode() + 288 | 31 * checkIR.hashCode + 289 | 37 * stdLib.hashCode + 290 | 41 * logLevel.hashCode 291 | 292 | } 293 | 294 | } 295 | 296 | } 297 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/Scalajsp.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import java.io.{Console => _, _} 4 | import java.util.zip.ZipFile 5 | 6 | import org.scalajs.core.ir.Printers.{IRTreePrinter, InfoPrinter} 7 | import org.scalajs.core.tools.io._ 8 | 9 | import scala.collection.immutable.Seq 10 | 11 | /** 12 | * Object used to translate sjsir files to something readable 13 | */ 14 | object Scalajsp { 15 | 16 | private val stdout = 17 | new BufferedWriter(new OutputStreamWriter(Console.out, "UTF-8")) 18 | 19 | /** 20 | * Returns the default options 21 | * 22 | * @return the default options 23 | */ 24 | def defaultOptions: Options = { 25 | Options() 26 | } 27 | 28 | /** 29 | * Executes scalajsp with the given Options 30 | * 31 | * @param givenOptions The options to use 32 | */ 33 | def execute(givenOptions: Options): Unit = { 34 | for { 35 | fileName <- givenOptions.fileNames 36 | } { 37 | val vfile = givenOptions.jar map { jar => 38 | readFromJar(jar, fileName) 39 | } getOrElse { 40 | readFromFile(fileName) 41 | } 42 | 43 | displayFileContent(vfile, givenOptions) 44 | } 45 | } 46 | 47 | private def displayFileContent(vfile: VirtualScalaJSIRFile, 48 | opts: Options): Unit = { 49 | if (opts.infos) 50 | new InfoPrinter(stdout).print(vfile.info) 51 | else 52 | new IRTreePrinter(stdout).printTopLevelTree(vfile.tree) 53 | 54 | stdout.flush() 55 | } 56 | 57 | private def readFromFile(fileName: String) = { 58 | val file = new File(fileName) 59 | 60 | if (!file.exists) 61 | fail(s"No such file: $fileName") 62 | else if (!file.canRead) 63 | fail(s"Unable to read file: $fileName") 64 | else 65 | FileVirtualScalaJSIRFile(file) 66 | } 67 | 68 | private def readFromJar(jar: File, name: String) = { 69 | val jarFile = 70 | try { 71 | new ZipFile(jar) 72 | } 73 | catch { 74 | case _: FileNotFoundException => fail(s"No such JAR: $jar") 75 | } 76 | try { 77 | val entry = jarFile.getEntry(name) 78 | if (entry == null) 79 | fail(s"No such file in jar: $name") 80 | else { 81 | val name = jarFile.getName + "#" + entry.getName 82 | val content = 83 | IO.readInputStreamToByteArray(jarFile.getInputStream(entry)) 84 | new MemVirtualSerializedScalaJSIRFile(name).withContent(content) 85 | } 86 | } finally { 87 | jarFile.close() 88 | } 89 | } 90 | 91 | private def fail(msg: String) = { 92 | Console.err.println(msg) 93 | sys.exit(1) 94 | } 95 | 96 | /** 97 | * Prints the supported Scala.js IR versions 98 | */ 99 | def printSupported(): Unit = { 100 | import org.scalajs.core.ir.ScalaJSVersions._ 101 | println(s"Emitted Scala.js IR version is: $binaryEmitted") 102 | println("Supported Scala.js IR versions are") 103 | binarySupported.foreach(v => println(s"* $v")) 104 | } 105 | 106 | /** 107 | * Options used to run Scalajsp 108 | * 109 | * @param infos If we only want the infos about the file and not its content 110 | * @param jar If the file to be read is in a jar 111 | * @param fileNames The files to read 112 | */ 113 | case class Options(infos: Boolean = false, 114 | jar: Option[File] = None, 115 | fileNames: Seq[String] = Seq.empty) { 116 | 117 | /** 118 | * Returns a new Options instance with the given infos value 119 | * 120 | * @param newInfos The new infos value 121 | * @return A new Options 122 | */ 123 | def withInfos(newInfos: Boolean): Options = { 124 | this.copy(infos = newInfos) 125 | } 126 | 127 | /** 128 | * Returns a new Options instance with the given jar value 129 | * 130 | * @param newJar The new jar value 131 | * @return A new Options 132 | */ 133 | def withJar(newJar: Option[File]): Options = { 134 | this.copy(jar = newJar) 135 | } 136 | 137 | /** 138 | * Returns a new Options instance with the given fileNames value 139 | * 140 | * @param newFilenames The new Filenames value 141 | * @return A new Options 142 | */ 143 | def withFileNames(newFilenames: Seq[String]): Options = { 144 | this.copy(fileNames = newFilenames) 145 | } 146 | 147 | } 148 | 149 | } -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/ClassScanner.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import java.io.File 4 | import java.lang.annotation.Annotation 5 | import java.net.{URL, URLClassLoader} 6 | import java.nio.file.Paths 7 | 8 | import sbt.testing._ 9 | 10 | import scala.collection.mutable.ArrayBuffer 11 | import scala.reflect.runtime.universe._ 12 | 13 | /** 14 | * An object used to retrieve TaskDef for ScalaJS 15 | */ 16 | object ClassScanner { 17 | 18 | /** 19 | * Finds all classes contained in an URLClassLoader which match to a fingerprint, or only those specified in explicitelySpecified 20 | * minus the ones in excluded 21 | * 22 | * @param classL The URLClassLoader 23 | * @param fingerprints The fingerprints to 24 | * @param explicitlySpecified A set of String to use as regex 25 | * @param excluded A set of String to use as regex 26 | * @return The TaskDefs found by the scan 27 | */ 28 | def scan(classL: URLClassLoader, fingerprints: Array[Fingerprint], explicitlySpecified: Set[String] = Set.empty, excluded: Set[String] = Set.empty): Array[TaskDef] = { 29 | 30 | def checkSuperclasses(c: Class[_], sF: SubclassFingerprint): Boolean = { 31 | 32 | def checkName(c: Class[_], fName: String): Boolean = { 33 | c.getName == fName || (c.getCanonicalName != null && c.getSimpleName == fName) || c.getCanonicalName == fName 34 | } 35 | 36 | 37 | def checkRec(c: Class[_], fName: String): Boolean = { 38 | if (checkName(c, fName)) { 39 | true 40 | } else { 41 | var sC = c.getSuperclass 42 | while (sC != null) { 43 | if (checkRec(sC, fName)) { 44 | return true 45 | } else { 46 | sC = sC.getSuperclass 47 | } 48 | } 49 | c.getInterfaces.exists(interf => checkRec(interf, fName)) 50 | } 51 | } 52 | 53 | checkRec(c, sF.superclassName()) 54 | } 55 | 56 | val objSuffix = "$" 57 | val classes = parseClasses(classL, explicitlySpecified, excluded) 58 | val buffer = ArrayBuffer[TaskDef]() 59 | classes.foreach(c => { 60 | fingerprints.foreach { 61 | case aF: AnnotatedFingerprint => 62 | try { 63 | val mirror = runtimeMirror(classL) 64 | val symb = mirror.classSymbol(c) 65 | val annotations = symb.annotations 66 | if ((c.isAnnotationPresent(Class.forName(aF.annotationName(), false, classL).asInstanceOf[Class[_ <: Annotation]]) 67 | || annotations.exists(a => a.tree.tpe.toString == aF.annotationName())) 68 | && (aF.isModule || (!aF.isModule && !c.getName.endsWith(objSuffix)))) { 69 | buffer += new TaskDef(c.getName.stripSuffix(objSuffix), aF, explicitlySpecified.nonEmpty, Array(new SuiteSelector)) 70 | } 71 | } catch { 72 | case e: ClassNotFoundException => 73 | Console.err.println("Class not found for annotation : " + aF.annotationName()) 74 | } 75 | case sF: SubclassFingerprint => 76 | if (checkSuperclasses(c, sF)) { 77 | if (!sF.requireNoArgConstructor || c.isInterface || (sF.requireNoArgConstructor && checkZeroArgsConstructor(c)) 78 | && (sF.isModule || (!sF.isModule && !c.getName.endsWith(objSuffix)))) { 79 | buffer += new TaskDef(c.getName.stripSuffix(objSuffix), sF, explicitlySpecified.nonEmpty, Array(new SuiteSelector)) 80 | } 81 | } 82 | case _ => throw new IllegalArgumentException("Unsupported Fingerprint type") 83 | } 84 | }) 85 | buffer.toArray.distinct 86 | } 87 | 88 | /** 89 | * Checks if the given class has a constructor with zero arguments 90 | * 91 | * @param c The class 92 | * @return true or false 93 | */ 94 | def checkZeroArgsConstructor(c: Class[_]): Boolean = { 95 | c.getDeclaredConstructors.exists(cons => cons.getParameterCount == 0) 96 | } 97 | 98 | /** 99 | * Finds all classes in a URLClassLoader, or only those specified by explicitelySpecified 100 | * minus the ones in excluded 101 | * 102 | * @param classL The URLClassLoader 103 | * @param explicitelySpecified A set of String to use as regex 104 | * @param excluded A set of String to use as regex 105 | * @return the classes 106 | */ 107 | def parseClasses(classL: URLClassLoader, explicitelySpecified: Set[String] = Set.empty, excluded: Set[String] = Set.empty): Array[Class[_]] = { 108 | 109 | val URIPathSep = '/' 110 | val extSep = '.' 111 | val ext = extSep + "class" 112 | 113 | def checkSpecific(name: String): Boolean = { 114 | !excluded.exists(s => s.r.pattern.matcher(name).matches()) && 115 | (explicitelySpecified.isEmpty || explicitelySpecified.exists(s => s.r.pattern.matcher(name).matches())) 116 | } 117 | 118 | def checkAndAddFile(file: File, buffer: ArrayBuffer[Class[_]], meth: () => Unit, packageName: String = ""): Unit = { 119 | if (!file.isDirectory && file.getName.endsWith(ext)) { 120 | val fileName = file.getName 121 | val name = packageName + fileName.substring(0, fileName.indexOf(extSep)) 122 | if (checkSpecific(name)) { 123 | buffer += classL.loadClass(name) 124 | } 125 | } else if (file.isDirectory) { 126 | meth() 127 | } 128 | } 129 | 130 | def parseClasses(url: URL, idx: Int, explicitlySpecified: Set[String] = Set.empty, excluded: Set[String] = Set.empty): Array[Class[_]] = { 131 | val f = Paths.get(url.toURI).toFile 132 | val packageName = { 133 | if (url != classL.getURLs()(idx)) { 134 | classL.getURLs()(idx).toURI.relativize(url.toURI).toString.replace(URIPathSep, extSep) 135 | } else { 136 | "" 137 | } 138 | } 139 | if (f.isDirectory) { 140 | val buffer = ArrayBuffer.empty[Class[_]] 141 | f.listFiles().foreach(file => { 142 | checkAndAddFile(file, buffer, () => parseClasses(file.toURI.toURL, idx, explicitlySpecified, excluded).foreach(c => { 143 | buffer += c 144 | }), packageName) 145 | }) 146 | buffer.toArray 147 | } else { 148 | if (f.getName.endsWith(ext)) { 149 | val fileName = f.getName 150 | val name = fileName.substring(0, fileName.indexOf(extSep)) 151 | if (checkSpecific(name)) { 152 | Array(classL.loadClass(packageName + name.substring(0, name.indexOf(extSep)))) 153 | } else { 154 | Array.empty[Class[_]] 155 | } 156 | } else { 157 | Array.empty[Class[_]] 158 | } 159 | } 160 | } 161 | 162 | val buffer = ArrayBuffer.empty[Class[_]] 163 | classL.getURLs.zipWithIndex.foreach(url => { 164 | val f = Paths.get(url._1.toURI).toFile 165 | checkAndAddFile(f, buffer, () => parseClasses(url._1, url._2, explicitelySpecified, excluded).foreach(c => { 166 | buffer += c 167 | })) 168 | }) 169 | buffer.toArray 170 | } 171 | } 172 | 173 | 174 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/FrameworkDetector.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import com.github.gtache.testing.FrameworkDetector.StoreConsole 4 | import org.scalajs.core.tools.io._ 5 | import org.scalajs.core.tools.json._ 6 | import org.scalajs.core.tools.linker.backend.ModuleKind 7 | import org.scalajs.core.tools.logging._ 8 | import org.scalajs.jsenv._ 9 | import org.scalajs.testadapter.ScalaJSFramework 10 | 11 | import scala.collection.mutable 12 | 13 | /* see https://github.com/scala-js/scala-js/blob/master/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/FrameworkDetector.scala */ 14 | /** 15 | * A class used to detect all available common TestFramework in a js file 16 | * 17 | * @param jsEnv The environment to use 18 | */ 19 | final class FrameworkDetector(jsEnv: JSEnv, 20 | moduleKind: ModuleKind = ModuleKind.NoModule, moduleIdentifier: Option[String] = None) { 21 | 22 | 23 | val jsGlobalExpr: String = { 24 | """((typeof global === "object" && global && 25 | global["Object"] === Object) ? global : this)""" 26 | } 27 | 28 | /** 29 | * Returns a list of instantiated ScalaJSFramework (one for each detected TestFramework). Calls detect() 30 | * 31 | * @param frameworks The list of TestFramework to search 32 | * @param logger The logger to use 33 | * @param console The jsConsole to use 34 | * @return The list of ScalaJSFramework 35 | */ 36 | def instantiatedScalaJSFrameworks(frameworks: Seq[TestFramework], logger: Logger, console: JSConsole): List[ScalaJSFramework] = { 37 | detect(frameworks).map(pair => { 38 | new ScalaJSFramework( 39 | pair._2, 40 | jsEnv.asInstanceOf[ComJSEnv], 41 | logger, 42 | console) 43 | }).toList 44 | } 45 | 46 | /** 47 | * Detects the TestFramework in a jsEnv, given a list of them. 48 | * 49 | * @param frameworks The frameworks to detect 50 | * @return A map linking a framework to it's common name 51 | */ 52 | def detect(frameworks: Seq[TestFramework]): Map[TestFramework, String] = { 53 | import com.github.gtache.testing.FrameworkDetector.ConsoleFrameworkPrefix 54 | val data = frameworks.map(_.classNames.toList).toList.toJSON 55 | 56 | val exportsNamespaceExpr = 57 | makeExportsNamespaceExpr(moduleKind, moduleIdentifier) 58 | 59 | val code = 60 | s""" 61 | (function(exportsNamespace) { 62 | "use strict"; 63 | /* #2752: if there is no testing framework at all on the classpath, 64 | * the testing interface will not be there, and therefore the 65 | * `detectFrameworks` function will not exist. We must therefore be 66 | * careful when selecting it. 67 | */ 68 | var namespace = exportsNamespace; 69 | namespace = namespace.org || {}; 70 | namespace = namespace.scalajs || {}; 71 | namespace = namespace.testinterface || {}; 72 | namespace = namespace.internal || {}; 73 | var detectFrameworksFun = namespace.detectFrameworks || (function(data) { 74 | var results = []; 75 | for (var i = 0; i < data.length; ++i) 76 | results.push(void 0); 77 | return results; 78 | }); 79 | var data = ${jsonToString(data)}; 80 | var results = detectFrameworksFun(data); 81 | for (var i = 0; i < results.length; ++i) { 82 | console.log("$ConsoleFrameworkPrefix" + (results[i] || "")); 83 | } 84 | })($exportsNamespaceExpr); 85 | """ 86 | 87 | val vf = new MemVirtualJSFile("frameworkDetector.js").withContent(code) 88 | val console = new StoreConsole 89 | 90 | val runner = jsEnv.jsRunner(vf) 91 | runner.run(NullLogger, console) 92 | 93 | // Filter jsDependencies unexpected output 94 | val results = console.buf collect { 95 | case s if s.startsWith(ConsoleFrameworkPrefix) => 96 | s.stripPrefix(ConsoleFrameworkPrefix) 97 | } 98 | 99 | assert(results.size == frameworks.size) 100 | 101 | (frameworks zip results).filter(_._2.nonEmpty).toMap 102 | } 103 | 104 | def makeExportsNamespaceExpr(moduleKind: ModuleKind, 105 | moduleIdentifier: Option[String]): String = { 106 | moduleKind match { 107 | case ModuleKind.NoModule => 108 | jsGlobalExpr 109 | 110 | case ModuleKind.CommonJSModule => 111 | import org.scalajs.core.ir.Utils.escapeJS 112 | val moduleIdent = moduleIdentifier.getOrElse { 113 | throw new IllegalArgumentException( 114 | "The module identifier must be specified for CommonJS modules") 115 | } 116 | s"""require("${escapeJS(moduleIdent)}")""" 117 | } 118 | } 119 | 120 | 121 | } 122 | 123 | object FrameworkDetector { 124 | 125 | private val ConsoleFrameworkPrefix = "@scalajs-test-framework-detector:" 126 | 127 | private class StoreConsole extends JSConsole { 128 | val buf: mutable.Buffer[String] = mutable.Buffer.empty[String] 129 | 130 | def log(msg: Any): Unit = buf += msg.toString 131 | } 132 | 133 | 134 | } 135 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/ScalaJSEventHandler.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import sbt.testing._ 4 | 5 | /** 6 | * Handles events fired by a Framework 7 | * 8 | * @param testStatus The ScalaJSTestStatus used to store the results 9 | */ 10 | final class ScalaJSEventHandler(testStatus: ScalaJSTestStatus) extends EventHandler { 11 | private var counterUnknown = 0 12 | private var counterKnown = 0 13 | 14 | override def handle(event: Event): Unit = { 15 | val fingerprint = event.fingerprint() 16 | val status = event.status() 17 | val selector = event.selector() 18 | 19 | var name = selector match { 20 | case n: NestedTestSelector => 21 | n.suiteId() + ':' + n.testName() 22 | case t: TestSelector => 23 | event.fullyQualifiedName() + ':' + t.testName() 24 | case s: SuiteSelector => 25 | event.fullyQualifiedName 26 | case n: NestedSuiteSelector => 27 | event.fullyQualifiedName() + '.' + n.suiteId() 28 | case t: TestWildcardSelector => 29 | t.testWildcard() 30 | case _ => throw new IllegalArgumentException("Unknown Selector") 31 | } 32 | 33 | name = name match { 34 | case "" => event.fullyQualifiedName() match { 35 | case "" => 36 | counterUnknown += 1 37 | "Unknown test (probably utest) #" + counterUnknown 38 | case _ => event.fullyQualifiedName() 39 | } 40 | case ":" => 41 | counterUnknown += 1 42 | "Unknown test (probably utest) #" + counterUnknown 43 | case _ => name 44 | } 45 | if (testStatus.all.map(t => t.fullyQualifiedName()).contains(name)) { 46 | counterKnown += 1 47 | name += ":" + counterKnown 48 | } 49 | val taskDef = new TaskDef(name, fingerprint, false, Array(selector)) 50 | testStatus.all = testStatus.all :+ taskDef 51 | status.name() match { 52 | case "Success" => 53 | testStatus.succeeded = testStatus.succeeded :+ taskDef 54 | 55 | case "Error" => 56 | testStatus.errored = testStatus.errored :+ taskDef 57 | 58 | case "Failure" => 59 | testStatus.failed = testStatus.failed :+ taskDef 60 | 61 | case "Skipped" => 62 | testStatus.skipped = testStatus.skipped :+ taskDef 63 | 64 | case "Ignored" => 65 | testStatus.ignored = testStatus.ignored :+ taskDef 66 | 67 | case "Canceled" => 68 | testStatus.canceled = testStatus.canceled :+ taskDef 69 | 70 | case "Pending" => 71 | testStatus.pending = testStatus.pending :+ taskDef 72 | 73 | case s: String => throw new IllegalStateException("Unknown task status : " + s) 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/ScalaJSTestResult.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import org.scalajs.testadapter.ScalaJSFramework 4 | import sbt.testing.TaskDef 5 | 6 | /** 7 | * An object containing the testing results. 8 | */ 9 | object ScalaJSTestResult { 10 | var statuses: Set[ScalaJSTestStatus] = Set.empty 11 | var lastStatuses: Set[ScalaJSTestStatus] = Set.empty 12 | 13 | /** 14 | * Returns all successful classes 15 | * 16 | * @return A set of classnames 17 | */ 18 | def successfulClassnames: Set[String] = { 19 | if (isFinished) { 20 | sanitizeClassnames(getSuccessfulNames).diff(failedClassnames) 21 | } else { 22 | println("Testing is not finished") 23 | Set.empty 24 | } 25 | } 26 | 27 | /** 28 | * Returns all failed classes 29 | * 30 | * @return A set of classnames 31 | */ 32 | def failedClassnames: Set[String] = { 33 | if (isFinished) { 34 | sanitizeClassnames(getErroredNames ++ getFailedNames) 35 | } else { 36 | println("Testing is not finished") 37 | Set.empty 38 | } 39 | } 40 | 41 | private def getErroredNames: Set[String] = { 42 | statuses.flatMap(s => s.errored).map(t => t.fullyQualifiedName()) 43 | } 44 | 45 | private def getFailedNames: Set[String] = { 46 | statuses.flatMap(s => s.failed).map(t => t.fullyQualifiedName()) 47 | } 48 | 49 | /** 50 | * Checks if testing is finished 51 | * 52 | * @return true or false 53 | */ 54 | def isFinished: Boolean = { 55 | !statuses.exists(s => !s.isFinished) 56 | } 57 | 58 | private def sanitizeClassnames(names: Set[String]): Set[String] = { 59 | names.map(s => s.takeWhile(c => c != ':')).filter(s => !s.contains('#')) 60 | } 61 | 62 | private def getSuccessfulNames: Set[String] = { 63 | statuses.flatMap(s => s.succeeded).map(t => t.fullyQualifiedName()) 64 | } 65 | 66 | /** 67 | * Returns the successful classes from the last run 68 | * 69 | * @return A set of classnames 70 | */ 71 | def getLastSuccessfulClassnames: Set[String] = { 72 | sanitizeClassnames(lastStatuses.flatMap(s => s.succeeded).map(t => t.fullyQualifiedName())).diff(getLastFailedClassnames) 73 | } 74 | 75 | /** 76 | * Returns the failed classes from the last run 77 | * 78 | * @return A set of classnames 79 | */ 80 | def getLastFailedClassnames: Set[String] = { 81 | sanitizeClassnames((lastStatuses.flatMap(s => s.failed) ++ lastStatuses.flatMap(s => s.errored)).map(t => t.fullyQualifiedName())) 82 | } 83 | 84 | /** 85 | * Returns the statuses from the last run 86 | * 87 | * @return A set of ScalaJSTestStatus 88 | */ 89 | def getLastStatuses: Set[ScalaJSTestStatus] = { 90 | lastStatuses 91 | } 92 | 93 | /** 94 | * Saves the statuses in lastStatuses and clear the current ones 95 | */ 96 | def save(): Unit = { 97 | lastStatuses = statuses 98 | statuses = Set.empty 99 | } 100 | 101 | override def toString: String = { 102 | "Testing result " + (if (!isFinished) { 103 | "(testing is not finished !)" 104 | } else "") + " : " + 105 | "\n--All : " + getAllNames.toList.sorted.mkString("\n\t") + 106 | "\n--Success : " + getSuccessfulNames.toList.sorted.mkString("\n\t") + 107 | "\n--Error : " + getErroredNames.toList.sorted.mkString("\n\t") + 108 | "\n--Failed : " + getFailedNames.toList.sorted.mkString("\n\t") + 109 | "\n--Skipped : " + getSkippedNames.toList.sorted.mkString("\n\t") + 110 | "\n--Ignored : " + getIgnoredNames.toList.sorted.mkString("\n\t") + 111 | "\n--Canceled : " + getCanceledNames.toList.sorted.mkString("\n\t") + 112 | "\n--Pending : " + getPendingNames.toList.sorted.mkString("\n\t") + 113 | (if (isSuccess) "\nAll tests passed" else "\nSome tests failed") 114 | } 115 | 116 | /** 117 | * Checks if all tests were successful 118 | * 119 | * @return true or false 120 | */ 121 | def isSuccess: Boolean = { 122 | if (isFinished) { 123 | getFailedNames.isEmpty && getErroredNames.isEmpty && getCanceledNames.isEmpty 124 | } else { 125 | println("Testing is not finished") 126 | false 127 | } 128 | } 129 | 130 | private def getCanceledNames: Set[String] = { 131 | statuses.flatMap(s => s.canceled).map(t => t.fullyQualifiedName()) 132 | } 133 | 134 | private def getAllNames: Set[String] = { 135 | statuses.flatMap(s => s.all).map(t => t.fullyQualifiedName()) 136 | } 137 | 138 | private def getSkippedNames: Set[String] = { 139 | statuses.flatMap(s => s.skipped).map(t => t.fullyQualifiedName()) 140 | } 141 | 142 | private def getIgnoredNames: Set[String] = { 143 | statuses.flatMap(s => s.ignored).map(t => t.fullyQualifiedName()) 144 | } 145 | 146 | private def getPendingNames: Set[String] = { 147 | statuses.flatMap(s => s.pending).map(t => t.fullyQualifiedName()) 148 | } 149 | 150 | /** 151 | * Returns the ScalaJSTestStatus for the given ScalaJSFramework 152 | * 153 | * @param f The framework 154 | * @return An option containing the framework, or None 155 | */ 156 | def getStatusFor(f: ScalaJSFramework): Option[ScalaJSFramework] = { 157 | statuses.find(s => f.name == s.framework.name).map(s => s.framework) 158 | } 159 | } 160 | 161 | /** 162 | * A class storing informations about a TestFramework (results of test) 163 | * 164 | * @param framework The framework which corresponds to this instance 165 | */ 166 | final class ScalaJSTestStatus(val framework: ScalaJSFramework) { 167 | var all: List[TaskDef] = List.empty 168 | var errored: List[TaskDef] = List.empty 169 | var failed: List[TaskDef] = List.empty 170 | var succeeded: List[TaskDef] = List.empty 171 | var skipped: List[TaskDef] = List.empty 172 | var ignored: List[TaskDef] = List.empty 173 | var canceled: List[TaskDef] = List.empty 174 | var pending: List[TaskDef] = List.empty 175 | var finished = false 176 | 177 | /** 178 | * Checks if testing is finished 179 | * 180 | * @return true or false 181 | */ 182 | def isFinished: Boolean = { 183 | finished 184 | } 185 | 186 | override def toString: String = { 187 | "ScalaJSTestStatus for " + framework.name + " : " + 188 | "\n--All : " + all.map(t => t.fullyQualifiedName()).mkString("\n\t") + 189 | "\n--Success : " + succeeded.map(t => t.fullyQualifiedName()).mkString("\n\t") + 190 | "\n--Error : " + errored.map(t => t.fullyQualifiedName()).mkString("\n\t") + 191 | "\n--Fail : " + failed.map(t => t.fullyQualifiedName()).mkString("\n\t") + 192 | "\n--Skip : " + skipped.map(t => t.fullyQualifiedName()).mkString("\n\t") + 193 | "\n--Ignored : " + ignored.map(t => t.fullyQualifiedName()).mkString("\n\t") + 194 | "\n--Canceled : " + canceled.map(t => t.fullyQualifiedName()).mkString("\n\t") + 195 | "\n--Pending : " + pending.map(t => t.fullyQualifiedName()).mkString("\n\t") 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/SimpleLogger.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import sbt.testing.Logger 4 | 5 | /* https://github.com/scala-js/scala-js/blob/02be3eafcce8d2c43ae4b133969a7d5817b74bc8/tools/js/src/test/scala/org/scalajs/core/tools/test/js/TestRunner.scala */ 6 | 7 | /** 8 | * A basic Logger for testing 9 | */ 10 | final class SimpleLogger extends Logger { 11 | def ansiCodesSupported(): Boolean = true 12 | 13 | def error(msg: String): Unit = println(msg) 14 | 15 | def warn(msg: String): Unit = println(msg) 16 | 17 | def info(msg: String): Unit = println(msg) 18 | 19 | def debug(msg: String): Unit = println(msg) 20 | 21 | def trace(t: Throwable): Unit = t.printStackTrace() 22 | } -------------------------------------------------------------------------------- /scalajs-plugin/src/main/scala/com/github/gtache/testing/TestFramework.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | 4 | /* sbt -- Simple Build Tool 5 | * Copyright 2008, 2009 Steven Blundy, Mark Harrah, Josh Cough 6 | */ 7 | /* https://github.com/sbt/sbt/blob/83f35b18d348d36611570642833976d0f6520a60/testing/src/main/scala/sbt/TestFramework.scala */ 8 | 9 | object TestFrameworks { 10 | val ScalaCheck = new TestFramework("org.scalacheck.ScalaCheckFramework") 11 | val ScalaTest = new TestFramework("org.scalatest.tools.Framework", "org.scalatest.tools.ScalaTestFramework") 12 | val Specs = new TestFramework("org.specs.runner.SpecsFramework") 13 | val Specs2 = new TestFramework("org.specs2.runner.Specs2Framework", "org.specs2.runner.SpecsFramework") 14 | val JUnit = new TestFramework("com.novocode.junit.JUnitFramework") 15 | 16 | val defaultFrameworks = Seq(ScalaCheck, ScalaTest, Specs, Specs2, JUnit) 17 | } 18 | 19 | /** 20 | * A simple container for a list of string representing implementing classes for a TestFramework 21 | * 22 | * @param classNames The names of the class which correspond to a framework 23 | */ 24 | class TestFramework(val classNames: String*) { 25 | 26 | } -------------------------------------------------------------------------------- /scalajs-plugin/src/test/groovy/com/github/gtache/PluginTest.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import com.github.gtache.tasks.CompileJSTask 4 | import com.google.common.collect.Sets 5 | import org.gradle.api.Project 6 | import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency 7 | import org.junit.Test 8 | import org.scalajs.core.tools.logging.Level 9 | import org.scalajs.core.tools.sem.Semantics 10 | import scala.Option 11 | 12 | import java.util.concurrent.locks.ReentrantLock 13 | 14 | import static com.github.gtache.BuildConfig.* 15 | import static com.github.gtache.Utils.* 16 | import static com.github.gtache.tasks.CompileJSTask.* 17 | 18 | class PluginTest extends GroovyTestCase { 19 | 20 | static final O_FILE = 'js2/js.js' 21 | static final OUTPUT_FILE = 'js2/js2.js' 22 | static final M_MODE = ECMA_6 23 | static final OUTPUT_MODE = ECMA_51_GLOBAL 24 | static final R_FILE = 'bla.js' 25 | static final REL_FILE = 'blabla.js' 26 | static final LOG_LEVEL = DEBUG 27 | 28 | @Test 29 | public void testAllConfigurations() { 30 | def optionsSet = [ 31 | MIN_OUTPUT + "=" + O_FILE, 32 | OUTPUT + "=" + OUTPUT_FILE, 33 | MIN_PRETTY, 34 | PRETTY, 35 | MIN_N_SOURCEMAP, 36 | N_SOURCEMAP, 37 | //"compliantAsInstanceOfs", 38 | MIN_OUTPUTMODE + "=" + M_MODE, 39 | OUTPUTMODE + "=" + OUTPUT_MODE, 40 | MIN_CHECKIR, 41 | CHECKIR, 42 | MIN_RELSM + "=" + R_FILE, 43 | RELSM + "=" + REL_FILE, 44 | CompileJSTask.LOG_LEVEL + "=" + LOG_LEVEL, 45 | MIN_DEBUG, 46 | DEBUG, 47 | MIN_WARN, 48 | WARN, 49 | MIN_ERR, 50 | ERR 51 | ].toSet() 52 | def outputSet = [MIN_OUTPUT + "=" + O_FILE, OUTPUT + "=" + OUTPUT_FILE].toSet() 53 | def outputModeSet = [MIN_OUTPUTMODE + "=" + M_MODE, OUTPUTMODE + "=" + OUTPUT_MODE].toSet() 54 | def sourceMapSet = [MIN_RELSM + "=" + R_FILE, RELSM + "=" + REL_FILE].toSet() 55 | def logLevelSet = [CompileJSTask.LOG_LEVEL + "=" + LOG_LEVEL, 56 | MIN_DEBUG, DEBUG, 57 | MIN_WARN, WARN, 58 | MIN_ERR, ERR].toSet() 59 | def setOptionsSet = new HashSet>() 60 | setOptionsSet.add(optionsSet) 61 | optionsSet.each { 62 | setOptionsSet.add([it].toSet()) 63 | } 64 | def ret = (Sets.powerSet(outputSet) + Sets.powerSet(outputModeSet) + Sets.powerSet(sourceMapSet) + Sets.powerSet(logLevelSet) + setOptionsSet).toList() 65 | def numThreads = Runtime.getRuntime().availableProcessors() 66 | def threadList = new ArrayList() 67 | def lock = new ReentrantLock() 68 | for (int i = 0; i < numThreads; ++i) { 69 | threadList.add(new Thread(new CheckRunnable(ret, i, numThreads, lock))) 70 | } 71 | for (int i = 0; i < numThreads; ++i) { 72 | threadList.get(i).start() 73 | } 74 | 75 | for (int i = 0; i < numThreads; ++i) { 76 | threadList.get(i).join() 77 | } 78 | 79 | } 80 | 81 | 82 | @Test 83 | public void testTasksPluginsDependenciesAdded() { 84 | def project = TestUtils.getFreshProject() 85 | TestUtils.applyPlugin(project) 86 | project.evaluate() 87 | def allTasks = [ 88 | "TestJS", 89 | "FastOptJS", 90 | "FullOptJS", 91 | "RunJS", 92 | "NoOptJS" 93 | ] 94 | allTasks.each { 95 | assertTrue(project.tasks.findByPath(it) != null) 96 | } 97 | 98 | def plugins = [ 99 | "java", 100 | "scala", 101 | "scalajs-plugin" 102 | ] 103 | 104 | plugins.each { 105 | assertTrue(project.plugins.findPlugin(it) != null) 106 | } 107 | 108 | def libDep = new DefaultExternalModuleDependency('org.scala-js', 'scalajs-library_' + SCALA_VERSION, SCALAJS_VERSION) 109 | def compDep = new DefaultExternalModuleDependency('org.scala-js', 'scalajs-compiler_' + SCALA_FULL_VERSION, SCALAJS_VERSION) 110 | def compileIt = project.configurations.getByName('compile').dependencies.iterator() 111 | def libDepFound = false 112 | while (compileIt.hasNext() && !libDepFound) { 113 | def dep = compileIt.next() 114 | if (libDep.group == dep.group && libDep.name == dep.name && libDep.version == dep.version) { 115 | libDepFound = true 116 | } 117 | } 118 | def scalaCompileIt = project.configurations.getByName('scalaCompilePlugin').dependencies.iterator() 119 | def compileDepFound = false 120 | while (scalaCompileIt.hasNext() && !compileDepFound) { 121 | def dep = scalaCompileIt.next() 122 | if (compDep.group == dep.group && compDep.name == dep.name && compDep.version == dep.version) { 123 | compileDepFound = true 124 | } 125 | } 126 | assertTrue(libDepFound && compileDepFound) 127 | deleteRecursive(project.projectDir) 128 | } 129 | 130 | private final class CheckRunnable implements Runnable { 131 | private final ArrayList> p 132 | private final int id 133 | private final int numThreads 134 | private final ReentrantLock lock 135 | private final int numOps 136 | private int counter = 0 137 | 138 | public CheckRunnable(List> p, int id, int numThreads, ReentrantLock lock) { 139 | this.p = p 140 | this.id = id 141 | this.numThreads = numThreads 142 | this.lock = lock 143 | this.numOps = p.size() / numThreads 144 | } 145 | 146 | @Override 147 | public void run() { 148 | final int lowerBound = numOps * id 149 | final int upperBound = (id == (numThreads - 1)) ? p.size() : (numOps * (id + 1)) 150 | for (int i = lowerBound; i < upperBound; ++i) { 151 | checkProperties(p.get(i)) 152 | counter += 1 153 | println("ID : " + id + " finished : " + counter + "/" + numOps) 154 | } 155 | } 156 | 157 | private void checkProperties(Set p) { 158 | lock.lock() 159 | final project = TestUtils.getFreshProject() 160 | lock.unlock() 161 | p.each { 162 | if (it.contains('=')) { 163 | def res = it.split("=") 164 | TestUtils.setProperty(project, res[0], res[1]) 165 | } else { 166 | TestUtils.setProperty(project, it) 167 | } 168 | } 169 | TestUtils.applyPlugin(project) 170 | project.evaluate() //Internal method, didn't find a way to do it (easily) via public API 171 | if (p.isEmpty()) { 172 | checkDefault(project) 173 | } 174 | p.each { 175 | checkProperty(it, p, project) 176 | } 177 | deleteRecursive(project.projectDir) 178 | } 179 | 180 | private void checkDefault(Project project) { 181 | final jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 182 | final jsBase = jsDir.absolutePath + File.separator + project.name 183 | final jsFile = project.file(jsBase + EXT) 184 | final jsFastFile = project.file(jsBase + FASTOPT_SUFFIX) 185 | final jsFullFile = project.file(jsBase + FULLOPT_SUFFIX) 186 | def options = ((CompileJSTask) project.tasks.findByName('FastOptJS')).options 187 | assertEquals(jsFastFile.path, options.output().path) 188 | assertEquals(Semantics.Defaults(), options.semantics()) 189 | assertEquals(Level.Info$.MODULE$, options.logLevel()) 190 | assertFalse(options.cp().isEmpty()) 191 | assertFalse(options.jsoutput()) 192 | assertTrue(options.sourceMap()) 193 | assertFalse(options.checkIR()) 194 | assertFalse(options.fullOpt()) 195 | assertFalse(options.noOpt()) 196 | assertFalse(options.prettyPrint()) 197 | assertEquals(Option.apply(null), options.stdLib()) 198 | assertEquals(Option.apply(null), options.relativizeSourceMap()) 199 | options = ((CompileJSTask) project.tasks.findByName('FullOptJS')).options 200 | assertEquals(jsFullFile.path, options.output().path) 201 | options = ((CompileJSTask) project.tasks.findByName('NoOptJS')).options 202 | assertEquals(jsFile.path, options.output().path) 203 | } 204 | 205 | private void checkProperty(String s, Set p, Project project) { 206 | final options = ((CompileJSTask) project.tasks.findByName('FastOptJS')).options 207 | switch (s) { 208 | case MIN_OUTPUT: 209 | def projectP = project.file(project.property(s)).path 210 | assertEquals(options.output().path, projectP) 211 | assertEquals(project.file(O_FILE).path, projectP) 212 | break 213 | case OUTPUT: 214 | if (!p.contains(MIN_OUTPUT)) { 215 | def projectP = project.file(project.property(s)).path 216 | assertEquals(options.output().path, project.file(project.property(s)).path) 217 | assertEquals(project.file(OUTPUT_FILE).path, projectP) 218 | } 219 | break 220 | case MIN_PRETTY: 221 | case PRETTY: 222 | assertTrue(options.prettyPrint()) 223 | break 224 | case MIN_N_SOURCEMAP: 225 | case N_SOURCEMAP: 226 | assertFalse(options.sourceMap()) 227 | break 228 | case COMPLIANT: 229 | //TODO 230 | break 231 | case MIN_OUTPUTMODE: 232 | assertEquals(options.outputMode(), getOutputMode((String) project.property(s))) 233 | assertEquals(M_MODE, (String) project.property(s)) 234 | break 235 | case OUTPUTMODE: 236 | if (!p.contains(MIN_OUTPUTMODE)) { 237 | assertEquals(options.outputMode(), getOutputMode((String) project.property(s))) 238 | assertEquals(OUTPUT_MODE, (String) project.property(s)) 239 | } 240 | break 241 | case MIN_CHECKIR: 242 | case CHECKIR: 243 | assertTrue(options.checkIR()) 244 | break 245 | case MIN_RELSM: 246 | def projectP = project.file(project.property(s)).path 247 | assertEquals(options.relativizeSourceMap().get(), project.file((String) project.property(s)).toURI()) 248 | assertEquals(project.file(R_FILE).path, projectP) 249 | break 250 | case RELSM: 251 | if (!p.contains(MIN_RELSM)) { 252 | def projectP = project.file(project.property(s)).path 253 | assertEquals(options.relativizeSourceMap().get(), project.file((String) project.property(s)).toURI()) 254 | assertEquals(project.file(REL_FILE).path, projectP) 255 | } 256 | break 257 | case CompileJSTask.LOG_LEVEL: 258 | if (!(p.contains(MIN_WARN) || p.contains(MIN_ERR) || p.contains(MIN_DEBUG) || 259 | p.contains(WARN) || p.contains(ERR) || p.contains(DEBUG))) { 260 | assertEquals( 261 | resolveLogLevel(project, (String) project.property(CompileJSTask.LOG_LEVEL), Level.Info$.MODULE$), 262 | options.logLevel()) 263 | assertEquals(LOG_LEVEL, (String) project.property(s)) 264 | } 265 | break 266 | case MIN_DEBUG: 267 | case DEBUG: 268 | assertEquals(Level.Debug$.MODULE$, options.logLevel()) 269 | break 270 | case MIN_WARN: 271 | case WARN: 272 | if (!(p.contains(MIN_DEBUG) || p.contains(DEBUG))) { 273 | assertEquals(Level.Warn$.MODULE$, options.logLevel()) 274 | } 275 | break 276 | case MIN_ERR: 277 | case ERR: 278 | if (!(p.contains(MIN_DEBUG) || p.contains(DEBUG) || 279 | p.contains(MIN_WARN) || p.contains(WARN))) { 280 | assertEquals(Level.Error$.MODULE$, options.logLevel()) 281 | } 282 | break 283 | default: 284 | break 285 | } 286 | } 287 | } 288 | 289 | } 290 | -------------------------------------------------------------------------------- /scalajs-plugin/src/test/groovy/com/github/gtache/TestUtils.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.testfixtures.ProjectBuilder 5 | 6 | import static com.github.gtache.BuildConfig.PLUGIN_VERSION 7 | import static com.github.gtache.BuildConfig.SCALA_FULL_VERSION 8 | 9 | class TestUtils { 10 | 11 | public static Project getFreshProject() { 12 | 13 | Project proj = ProjectBuilder.builder().build() 14 | 15 | proj.buildscript { 16 | repositories { 17 | mavenLocal() 18 | mavenCentral() 19 | } 20 | dependencies { 21 | classpath 'com.github.gtache:scalajs-plugin:' + PLUGIN_VERSION 22 | } 23 | } 24 | proj.repositories { 25 | mavenCentral() 26 | } 27 | 28 | proj.pluginManager.apply('java') 29 | 30 | proj.pluginManager.apply('scala') 31 | 32 | proj.dependencies { 33 | compile 'org.scala-lang:scala-compiler:' + SCALA_FULL_VERSION 34 | compile 'org.scala-lang:scala-library:' + SCALA_FULL_VERSION 35 | } 36 | return proj 37 | } 38 | 39 | public static void applyPlugin(Project project) { 40 | project.pluginManager.apply('scalajs-plugin') 41 | } 42 | 43 | public static void setProperty(Project project, String key, Object value = true) { 44 | project.extensions.add(key, value) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /scalajs-plugin/src/test/groovy/com/github/gtache/UtilsTest.groovy: -------------------------------------------------------------------------------- 1 | package com.github.gtache 2 | 3 | import com.github.gtache.testing.TestFramework 4 | import org.gradle.api.Project 5 | import org.junit.Test 6 | import org.scalajs.core.tools.linker.backend.OutputMode 7 | import org.scalajs.core.tools.logging.Level 8 | import org.scalajs.jsenv.nodejs.NodeJSEnv 9 | import org.scalajs.jsenv.phantomjs.PhantomJSEnv 10 | import org.scalajs.jsenv.rhino.RhinoJSEnv 11 | import scala.collection.mutable.ArrayBuffer 12 | 13 | import static com.github.gtache.TestUtils.* 14 | import static com.github.gtache.Utils.* 15 | import static com.github.gtache.tasks.CompileJSTask.MIN_OUTPUT 16 | import static com.github.gtache.tasks.CompileJSTask.OUTPUT 17 | 18 | class UtilsTest extends GroovyTestCase { 19 | 20 | @Test 21 | public void testResolvePath() { 22 | Project project = getFreshProject() 23 | final dummyString = 'foo/bar.js' 24 | def jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 25 | def jsPath = project.file(jsDir.path + File.separator + project.name + EXT).path 26 | def jsFastPath = project.file(jsDir.path + File.separator + project.name + FASTOPT_SUFFIX).path 27 | def jsFullPath = project.file(jsDir.path + File.separator + project.name + FULLOPT_SUFFIX).path 28 | def dummyPath = project.file(dummyString).toString() 29 | applyPlugin(project) 30 | assertEquals(jsFastPath, resolvePath(project)) 31 | deleteRecursive(project.projectDir) 32 | 33 | project = getFreshProject() 34 | jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 35 | jsPath = project.file(jsDir.path + File.separator + project.name + EXT).path 36 | jsFastPath = project.file(jsDir.path + File.separator + project.name + FASTOPT_SUFFIX).path 37 | jsFullPath = project.file(jsDir.path + File.separator + project.name + FULLOPT_SUFFIX).path 38 | setProperty(project, RUN_FULL) 39 | applyPlugin(project) 40 | assertEquals(jsFullPath, resolvePath(project)) 41 | deleteRecursive(project.projectDir) 42 | 43 | project = getFreshProject() 44 | jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 45 | jsPath = project.file(jsDir.path + File.separator + project.name + EXT).path 46 | jsFastPath = project.file(jsDir.path + File.separator + project.name + FASTOPT_SUFFIX).path 47 | jsFullPath = project.file(jsDir.path + File.separator + project.name + FULLOPT_SUFFIX).path 48 | setProperty(project, RUN_NOOPT) 49 | applyPlugin(project) 50 | assertEquals(jsPath, resolvePath(project)) 51 | deleteRecursive(project.projectDir) 52 | 53 | project = getFreshProject() 54 | jsDir = project.file(project.buildDir.absolutePath + JS_REL_DIR) 55 | jsPath = project.file(jsDir.path + File.separator + project.name + EXT).path 56 | jsFastPath = project.file(jsDir.path + File.separator + project.name + FASTOPT_SUFFIX).path 57 | jsFullPath = project.file(jsDir.path + File.separator + project.name + FULLOPT_SUFFIX).path 58 | setProperty(project, RUN_FULL) 59 | setProperty(project, RUN_NOOPT) 60 | applyPlugin(project) 61 | assertEquals(jsFullPath, resolvePath(project)) 62 | deleteRecursive(project.projectDir) 63 | 64 | project = getFreshProject() 65 | dummyPath = project.file(dummyString).toString() 66 | setProperty(project, MIN_OUTPUT, dummyString) 67 | applyPlugin(project) 68 | assertEquals(dummyPath, resolvePath(project)) 69 | deleteRecursive(project.projectDir) 70 | 71 | project = getFreshProject() 72 | dummyPath = project.file(dummyString).toString() 73 | setProperty(project, OUTPUT, dummyString) 74 | applyPlugin(project) 75 | assertEquals(dummyPath, resolvePath(project)) 76 | deleteRecursive(project.projectDir) 77 | 78 | project = getFreshProject() 79 | dummyPath = project.file(dummyString).toString() 80 | setProperty(project, MIN_OUTPUT, dummyString) 81 | setProperty(project, OUTPUT, 'blabla/bla.js') 82 | applyPlugin(project) 83 | assertEquals(dummyPath, resolvePath(project)) 84 | deleteRecursive(project.projectDir) 85 | 86 | project = getFreshProject() 87 | dummyPath = project.file(dummyString).toString() 88 | setProperty(project, MIN_OUTPUT, dummyString) 89 | setProperty(project, RUN_FULL) 90 | applyPlugin(project) 91 | assertEquals(dummyPath, resolvePath(project)) 92 | deleteRecursive(project.projectDir) 93 | 94 | project = getFreshProject() 95 | dummyPath = project.file(dummyString).toString() 96 | setProperty(project, OUTPUT, dummyString) 97 | setProperty(project, RUN_FULL) 98 | applyPlugin(project) 99 | assertEquals(dummyPath, resolvePath(project)) 100 | deleteRecursive(project.projectDir) 101 | 102 | } 103 | 104 | @Test 105 | public void testResolveEnv() { 106 | Project project = getFreshProject() 107 | applyPlugin(project) 108 | assertEquals(NodeJSEnv.class, resolveEnv(project).getClass()) 109 | deleteRecursive(project.projectDir) 110 | 111 | project = getFreshProject() 112 | setProperty(project, RHINO) 113 | applyPlugin(project) 114 | assertEquals(RhinoJSEnv.class, resolveEnv(project).getClass()) 115 | deleteRecursive(project.projectDir) 116 | 117 | project = getFreshProject() 118 | setProperty(project, PHANTOM) 119 | applyPlugin(project) 120 | assertEquals(PhantomJSEnv.class, resolveEnv(project).getClass()) 121 | deleteRecursive(project.projectDir) 122 | 123 | } 124 | 125 | @Test 126 | public void testResolveLogLevel() { 127 | final String log = "logLevel" 128 | Project project = getFreshProject() 129 | applyPlugin(project) 130 | assertEquals(Level.Debug$.MODULE$, resolveLogLevel(project, log, Level.Debug$.MODULE$)) 131 | assertEquals(Level.Info$.MODULE$, resolveLogLevel(project, log, Level.Info$.MODULE$)) 132 | assertEquals(Level.Warn$.MODULE$, resolveLogLevel(project, log, Level.Warn$.MODULE$)) 133 | assertEquals(Level.Error$.MODULE$, resolveLogLevel(project, log, Level.Error$.MODULE$)) 134 | deleteRecursive(project.projectDir) 135 | 136 | project = getFreshProject() 137 | setProperty(project, log, "Warn") 138 | applyPlugin(project) 139 | assertEquals(Level.Warn$.MODULE$, resolveLogLevel(project, log, Level.Debug$.MODULE$)) 140 | deleteRecursive(project.projectDir) 141 | 142 | project = getFreshProject() 143 | setProperty(project, log, "Error") 144 | assertEquals(Level.Error$.MODULE$, resolveLogLevel(project, log, Level.Debug$.MODULE$)) 145 | deleteRecursive(project.projectDir) 146 | 147 | project = getFreshProject() 148 | setProperty(project, log, "Debug") 149 | assertEquals(Level.Debug$.MODULE$, resolveLogLevel(project, log, Level.Warn$.MODULE$)) 150 | deleteRecursive(project.projectDir) 151 | 152 | project = getFreshProject() 153 | setProperty(project, log, "Info") 154 | assertEquals(Level.Info$.MODULE$, resolveLogLevel(project, log, Level.Debug$.MODULE$)) 155 | deleteRecursive(project.projectDir) 156 | } 157 | 158 | @Test 159 | public void testGetOutputMode() { 160 | assertEquals(OutputMode.ECMAScript51Global$.MODULE$, getOutputMode(ECMA_51_GLOBAL)) 161 | assertEquals(OutputMode.ECMAScript51Isolated$.MODULE$, getOutputMode(ECMA_51_ISOLATED)) 162 | assertEquals(OutputMode.ECMAScript6$.MODULE$, getOutputMode(ECMA_6)) 163 | } 164 | 165 | @Test 166 | public void testGetMinimalDependencySeq() { 167 | final Project project = getFreshProject() 168 | final jsFastPath = project.name + FASTOPT_SUFFIX 169 | applyPlugin(project) 170 | final seq = getMinimalDependencySeq(project) 171 | assertEquals(1, seq.size()) 172 | assertEquals(jsFastPath, seq.apply(0).lib().name()) 173 | deleteRecursive(project.projectDir) 174 | } 175 | 176 | @Test 177 | public void testDeleteRecursive() { 178 | final Project project = getFreshProject() 179 | final File root = project.file('test') 180 | root.mkdir() 181 | final File file1 = project.file('test/1') 182 | final File file2 = project.file('test/2') 183 | final File dir1 = project.file('test/dir1') 184 | final File dir2 = project.file('test/dir2') 185 | dir1.mkdir() 186 | dir2.mkdir() 187 | final File file3 = project.file('test/dir1/1') 188 | final File file4 = project.file('test/dir1/2') 189 | final Set allFiles = [root, dir1, dir2, file1, file2, file3, file4].toSet() 190 | allFiles.each { 191 | if (it.isDirectory()) { 192 | assertTrue(it.exists()) 193 | } else { 194 | assertFalse(it.exists()) 195 | } 196 | } 197 | file1.createNewFile() 198 | file2.createNewFile() 199 | file3.createNewFile() 200 | file4.createNewFile() 201 | assertEquals(4, root.listFiles().size()) 202 | assertEquals(2, dir1.listFiles().size()) 203 | assertEquals(0, dir2.listFiles().size()) 204 | allFiles.each { 205 | assertTrue(it.exists()) 206 | } 207 | deleteRecursive(root) 208 | allFiles.each { 209 | assertFalse(it.exists()) 210 | } 211 | deleteRecursive(project.projectDir) 212 | } 213 | 214 | @Test 215 | public void testTaskInStartParameter() { 216 | final Project project = getFreshProject() 217 | final List tasks = new ArrayList<>() 218 | tasks.add("TeSTJs") 219 | tasks.add("blaJS") 220 | project.gradle.startParameter.setTaskNames(tasks) 221 | assertTrue(isTaskInStartParameter(project, "testjs")) 222 | assertTrue(isTaskInStartParameter(project, "blaJS")) 223 | assertFalse(isTaskInStartParameter(project, "something")) 224 | deleteRecursive(project.projectDir) 225 | } 226 | 227 | @Test 228 | public void testResolveTestFrameworks() { 229 | Project project = getFreshProject() 230 | assertTrue(resolveTestFrameworks(project).isEmpty()) 231 | deleteRecursive(project.projectDir) 232 | project = getFreshProject() 233 | final List testFrameworks = new ArrayList<>() 234 | final String test1 = "com.test.Test1" 235 | final String test2 = "com.test.Test2" 236 | testFrameworks.add(test1) 237 | testFrameworks.add(test2) 238 | project.extensions.add(TEST_FRAMEWORKS, testFrameworks) 239 | final List resolvedFrameworks = resolveTestFrameworks(project) 240 | assertEquals(2, resolvedFrameworks.size()) 241 | final List> resolvedFrameworksName = resolvedFrameworks.collect { 242 | it.classNames() 243 | } 244 | boolean found1 = false 245 | boolean found2 = false 246 | resolvedFrameworksName.each { 247 | if (it.contains(test1)) { 248 | found1 = true 249 | } 250 | if (it.contains(test2)) { 251 | found2 = true 252 | } 253 | } 254 | assertTrue(found1 && found2) 255 | deleteRecursive(project.projectDir) 256 | } 257 | 258 | @Test 259 | public void testToRegex() { 260 | assertEquals("com\\..*", toRegex("com.*")) 261 | assertEquals("com\\.github\\.gtache", toRegex("com.github.gtache")) 262 | assertEquals(".*", toRegex("*")) 263 | assertEquals("com\\\\gtache", toRegex("com\\gtache")) 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /scalajs-plugin/src/test/java/com/github/gtache/testing/JavaAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | @Retention(RetentionPolicy.RUNTIME) 7 | public @interface JavaAnnotation { 8 | } 9 | -------------------------------------------------------------------------------- /scalajs-plugin/src/test/scala/com/github/gtache/testing/ClassScannerTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.gtache.testing 2 | 3 | import java.net.{URL, URLClassLoader} 4 | 5 | import com.github.gtache.Utils 6 | import org.junit.Assert._ 7 | import org.junit.Test 8 | import sbt.testing.{AnnotatedFingerprint, Fingerprint, SubclassFingerprint} 9 | 10 | import scala.annotation.StaticAnnotation 11 | 12 | class ClassScannerTest { 13 | 14 | val packageName = "com.github.gtache.testing." 15 | 16 | val annFingerprint = new AnnotatedFingerprint { 17 | override def isModule: Boolean = true 18 | 19 | override def annotationName(): String = packageName + "JavaAnnotation" 20 | } 21 | 22 | val scalAnnFingerprint = new AnnotatedFingerprint { 23 | override def isModule: Boolean = false 24 | 25 | override def annotationName(): String = packageName + "ScalaAnnotation" 26 | } 27 | 28 | val subFingerprint = new SubclassFingerprint { 29 | override def isModule: Boolean = true 30 | 31 | override def superclassName(): String = packageName + "A" 32 | 33 | override def requireNoArgConstructor(): Boolean = true 34 | } 35 | 36 | val subFingerprint2 = new SubclassFingerprint { 37 | override def requireNoArgConstructor(): Boolean = false 38 | 39 | override def isModule: Boolean = true 40 | 41 | override def superclassName(): String = packageName + "G" 42 | } 43 | 44 | val subFingerprint3 = new SubclassFingerprint { 45 | override def requireNoArgConstructor(): Boolean = true 46 | 47 | override def isModule: Boolean = true 48 | 49 | override def superclassName(): String = packageName + "K" 50 | } 51 | 52 | val fingerprints: Array[Fingerprint] = Array(annFingerprint, scalAnnFingerprint, subFingerprint, subFingerprint2, subFingerprint3) 53 | val test: URL = this.getClass.getResource("../../../../") 54 | val loader = new URLClassLoader(Array(test)) 55 | 56 | val explicitlySpecified: Set[String] = Set("*A*", "*B", "*C").map(Utils.toRegex) 57 | val excluded: Set[String] = Set("*C", "*H").map(Utils.toRegex) 58 | val excludedAll: Set[String] = Set(Utils.toRegex("com.*")) 59 | val explicitlyEmpty: Set[String] = Set(Utils.toRegex("co.*")) 60 | val all = Set(packageName + "A", packageName + "AB", packageName + "B", packageName + "C", packageName + "D", 61 | packageName + "E", packageName + "F", packageName + "G", packageName + "H", packageName + "I", packageName + "J", 62 | packageName + "K", packageName + "L", packageName + "M", packageName + "N") 63 | 64 | @Test 65 | def testScannerBasic(): Unit = { 66 | val taskDefs = ClassScanner.scan(loader, fingerprints) 67 | 68 | val nameTasks = taskDefs.map(t => t.fullyQualifiedName()) 69 | val contained = Set(packageName + "A", packageName + "AB", packageName + "B", packageName + "C", packageName + "D", packageName + "F", 70 | packageName + "G", packageName + "H", packageName + "J", packageName + "K", packageName + "M") 71 | checkContains(nameTasks.toSet, contained, all) 72 | 73 | 74 | val map = nameTasks.zip(taskDefs).toMap 75 | assertTrue(map(packageName + "A").fingerprint.isInstanceOf[SubclassFingerprint]) 76 | assertTrue(map(packageName + "AB").fingerprint.isInstanceOf[SubclassFingerprint]) 77 | assertTrue(map(packageName + "B").fingerprint.isInstanceOf[SubclassFingerprint]) 78 | assertTrue(map(packageName + "C").fingerprint.isInstanceOf[SubclassFingerprint]) 79 | assertTrue(map(packageName + "D").fingerprint.isInstanceOf[AnnotatedFingerprint]) 80 | assertTrue(map(packageName + "F").fingerprint.isInstanceOf[AnnotatedFingerprint]) 81 | assertTrue(map(packageName + "G").fingerprint.isInstanceOf[SubclassFingerprint]) 82 | assertTrue(map(packageName + "H").fingerprint.isInstanceOf[SubclassFingerprint]) 83 | assertTrue(map(packageName + "J").fingerprint.isInstanceOf[SubclassFingerprint]) 84 | assertTrue(map(packageName + "K").fingerprint.isInstanceOf[SubclassFingerprint]) 85 | assertTrue(map(packageName + "M").fingerprint.isInstanceOf[AnnotatedFingerprint]) 86 | } 87 | 88 | def checkContains(nameTasks: Set[String], contained: Set[String], all: Set[String]): Unit = { 89 | contained.foreach { s => 90 | assertTrue(s + " in " + contained.mkString(" ; "), nameTasks.contains(s)) 91 | } 92 | all.filterNot(contained).foreach { s => 93 | assertFalse(s + " not in " + contained.mkString(" ; "), nameTasks.contains(s)) 94 | } 95 | } 96 | 97 | @Test 98 | def testScannerExplicitely(): Unit = { 99 | val taskDefs = ClassScanner.scan(loader, fingerprints, explicitlySpecified) 100 | val nameTasks = taskDefs.map(t => t.fullyQualifiedName()) 101 | val contained = Set(packageName + "A", packageName + "AB", packageName + "B", packageName + "C") 102 | checkContains(nameTasks.toSet, contained, all) 103 | 104 | val map = nameTasks.zip(taskDefs).toMap 105 | assertTrue(map(packageName + "A").fingerprint.isInstanceOf[SubclassFingerprint]) 106 | assertTrue(map(packageName + "AB").fingerprint.isInstanceOf[SubclassFingerprint]) 107 | assertTrue(map(packageName + "B").fingerprint.isInstanceOf[SubclassFingerprint]) 108 | assertTrue(map(packageName + "C").fingerprint.isInstanceOf[SubclassFingerprint]) 109 | } 110 | 111 | @Test 112 | def testScannerExcluded(): Unit = { 113 | val taskDefs = ClassScanner.scan(loader, fingerprints, explicitlySpecified, excluded) 114 | val nameTasks = taskDefs.map(t => t.fullyQualifiedName()) 115 | val contained = Set(packageName + "A", packageName + "AB", packageName + "B") 116 | checkContains(nameTasks.toSet, contained, all) 117 | 118 | val map = nameTasks.zip(taskDefs).toMap 119 | assertTrue(map(packageName + "A").fingerprint.isInstanceOf[SubclassFingerprint]) 120 | assertTrue(map(packageName + "AB").fingerprint.isInstanceOf[SubclassFingerprint]) 121 | assertTrue(map(packageName + "B").fingerprint.isInstanceOf[SubclassFingerprint]) 122 | } 123 | 124 | @Test 125 | def testScannerExcludedAll(): Unit = { 126 | var taskDefs = ClassScanner.scan(loader, fingerprints, explicitlySpecified, excludedAll) 127 | assertTrue(taskDefs.isEmpty) 128 | taskDefs = ClassScanner.scan(loader, fingerprints, Set.empty, excludedAll) 129 | assertTrue(taskDefs.isEmpty) 130 | } 131 | 132 | @Test 133 | def testScannerExcludedEmpty(): Unit = { 134 | val taskDefs = ClassScanner.scan(loader, fingerprints, explicitlyEmpty) 135 | assertTrue(taskDefs.isEmpty) 136 | } 137 | 138 | 139 | } 140 | 141 | class A 142 | 143 | class B extends A 144 | 145 | class C extends B 146 | 147 | @JavaAnnotation 148 | class D 149 | 150 | class E(s: String) extends A { 151 | 152 | } 153 | 154 | @JavaAnnotation 155 | class F(s: String) extends A { 156 | 157 | } 158 | 159 | class G(s: String) 160 | 161 | class H(s: String, i: Int) extends G(s) 162 | 163 | class I 164 | 165 | trait J extends K 166 | 167 | trait K 168 | 169 | trait L 170 | 171 | object AB extends I with J 172 | 173 | @ScalaAnnotation 174 | class M 175 | 176 | @ScalaAnnotation 177 | object N 178 | 179 | class ScalaAnnotation extends StaticAnnotation --------------------------------------------------------------------------------