Gradle, Kotlin/JS: enable source maps by default, get it working on tests.

Publish kotlin-test-nodejs-runner separately from kotlin-gradle-plugin.
This commit is contained in:
Sergey Rostov
2019-03-25 15:39:03 +03:00
parent a4cbec64b7
commit 0e0c78317d
17 changed files with 586 additions and 135 deletions
@@ -68,7 +68,8 @@ projectTest {
":examples:annotation-processor-example:install",
":kotlin-scripting-common:install",
":kotlin-scripting-jvm:install",
":kotlin-scripting-compiler-embeddable:install"
":kotlin-scripting-compiler-embeddable:install",
":kotlin-test-nodejs-runner:install"
)
exclude(jpsIncrementalTestsClass)
}
@@ -380,6 +380,24 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() {
assertFileExists(moduleDir + "kotlin-js-plugin-1.0-sources.jar")
assertFileExists("build/test_node_modules/kotlin.js")
assertFileExists("build/test_node_modules/kotlin.js.map")
assertFileExists("build/test_node_modules/kotlin-test.js")
assertFileExists("build/test_node_modules/kotlin-test.js.map")
assertFileExists("build/test_node_modules/kotlin-test-nodejs-runner.js")
assertFileExists("build/test_node_modules/kotlin-test-nodejs-runner.js.map")
assertFileExists("build/test_node_modules/kotlin-nodejs-source-map-support.js")
assertFileExists("build/test_node_modules/kotlin-nodejs-source-map-support.js.map")
assertFileExists("build/test_node_modules/kotlin-js-plugin.js")
assertFileExists("build/test_node_modules/kotlin-js-plugin.js.map")
assertFileExists("build/test_node_modules/kotlin-js-plugin_test.js")
assertFileExists("build/test_node_modules/kotlin-js-plugin_test.js.map")
assertFileContains(
"build/test_node_modules/kotlin-js-plugin_test.js.map",
"\"sources\":[\"../../src/test/kotlin/MainTest.kt\"]"
)
assertTestResults("testProject/kotlin-js-plugin-project/tests.xml", "test")
}
}
@@ -311,8 +311,6 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksRegisteredAndNotRealized(
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
@@ -325,8 +323,6 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksExecuted(
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
@@ -334,6 +330,24 @@ class MultiplatformGradleIT : BaseGradleIT() {
":serverTest"
)
assertFileExists("build/client_test_node_modules/kotlin.js")
assertFileExists("build/client_test_node_modules/kotlin.js.map")
assertFileExists("build/client_test_node_modules/kotlin-test.js")
assertFileExists("build/client_test_node_modules/kotlin-test.js.map")
assertFileExists("build/client_test_node_modules/kotlin-test-nodejs-runner.js")
assertFileExists("build/client_test_node_modules/kotlin-test-nodejs-runner.js.map")
assertFileExists("build/client_test_node_modules/kotlin-nodejs-source-map-support.js")
assertFileExists("build/client_test_node_modules/kotlin-nodejs-source-map-support.js.map")
assertFileExists("build/client_test_node_modules/new-mpp-js-tests.js")
assertFileExists("build/client_test_node_modules/new-mpp-js-tests.js.map")
assertFileExists("build/client_test_node_modules/new-mpp-js-tests_test.js")
assertFileExists("build/client_test_node_modules/new-mpp-js-tests_test.js.map")
assertFileContains(
"build/client_test_node_modules/new-mpp-js-tests_test.js.map",
"\"sources\":[\"../../src/commonTest/kotlin/CommonTest.kt\"]"
)
assertTestResults("testProject/new-mpp-js-tests/TEST-CommonTest.xml", "clientTest")
assertTestResults("testProject/new-mpp-js-tests/TEST-CommonTest.xml", "serverTest")
}
@@ -343,8 +357,6 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksUpToDate(
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
@@ -359,10 +371,6 @@ class MultiplatformGradleIT : BaseGradleIT() {
build("check") {
assertSuccessful()
assertTasksUpToDate(
":kotlinNodeJsTestRuntimeExtract"
)
assertTasksExecuted(
":clientTestNodeModules",
":clientTest",
@@ -46,6 +46,8 @@ dependencies {
compileOnly(project(":kotlin-annotation-processing-gradle"))
compileOnly(project(":kotlin-scripting-compiler"))
compile("com.google.code.gson:gson:2.8.5")
compileOnly("com.android.tools.build:gradle:2.0.0")
compileOnly("com.android.tools.build:gradle-core:2.0.0")
compileOnly("com.android.tools.build:builder:2.0.0")
@@ -62,8 +64,7 @@ dependencies {
runtime(projectRuntimeJar(":kotlin-scripting-compiler-embeddable"))
runtime(project(":kotlin-reflect"))
jarContents(compileOnly(intellijDep()) { includeJars("serviceMessages") })
jarContents(projectArchives(":kotlin-test-nodejs-runner"))
jarContents(compileOnly(intellijDep()) { includeJars("serviceMessages", "gson-2.8.5") })
// com.android.tools.build:gradle has ~50 unneeded transitive dependencies
compileOnly("com.android.tools.build:gradle:3.0.0") { isTransitive = false }
@@ -63,6 +63,10 @@ internal class KotlinJsCompilationTestsConfigurator(
get() = classpath.plus(project.files(destinationDir))
fun configure() {
compilation.dependencies {
implementation(kotlin("test-nodejs-runner"))
}
val nodeModulesTask = registerTask(
project,
disambiguateCamelCased("nodeModules", true),
@@ -79,20 +83,13 @@ internal class KotlinJsCompilationTestsConfigurator(
}
val projectWithNodeJsPlugin = NodeJsPlugin.ensureAppliedInHierarchy(target.project)
val kotlinJsExtractTestRunnerTask = project.kotlinNodeJsTestRuntimeExtractTask
val testTask = registerTask(project, testTaskName, KotlinNodeJsTestTask::class.java) { testJs ->
testJs.group = "verification"
testJs.dependsOn(
nodeModulesTask.getTaskOrProvider(),
kotlinJsExtractTestRunnerTask.getTaskOrProvider()
)
testJs.dependsOn(nodeModulesTask.getTaskOrProvider())
testJs.onlyIf {
// run only if there is org.jetbrains.kotlin:kotlin-test-js in classpath
// (kotlin-test-nodejs-runner.js requires kotlin-test.js)
nodeModulesDir.resolve("kotlin-test.js").exists()
compileTestKotlin2Js.outputFile.exists()
}
@@ -103,7 +100,10 @@ internal class KotlinJsCompilationTestsConfigurator(
testJs.nodeJsProcessOptions.workingDir = project.projectDir
testJs.nodeModulesDir = nodeModulesDir
testJs.testRuntimeNodeModule = project.extractedKotlinTestNodeJsRunner
testJs.testRuntimeNodeModules = listOf(
"kotlin-test-nodejs-runner.js",
"kotlin-nodejs-source-map-support.js"
)
testJs.nodeModulesToLoad = setOf(compileTestKotlin2Js.outputFile.name)
val htmlReport = DslObject(testJs.reports.html)
@@ -22,7 +22,11 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
super.configureCompilations(platformTarget)
platformTarget.compilations.all {
it.compileKotlinTask.kotlinOptions.moduleKind = "umd"
it.compileKotlinTask.kotlinOptions {
moduleKind = "umd"
sourceMap = true
sourceMapEmbedSources = null
}
}
}
@@ -0,0 +1,210 @@
package org.jetbrains.kotlin.gradle.targets.js.internal
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import com.google.gson.stream.MalformedJsonException
import org.slf4j.LoggerFactory
import java.io.*
open class RewriteSourceMapFilterReader(
val input: Reader
) : FilterReader(input) {
// This implementation works only when source map contents starts
// with prolog `{"version":3,"file":"...","sources":[...],"sourcesContent":...`
// This is always true for Kotlin/JS and many other tools that produces JS source maps.
//
// Full implementation (without loading file contents entirely into memory) requires
// streaming read of string literals inside "mappings", which is not supported by any
// known JSON parsers. We cannot store "mappings" into memory since it can reach tens
// of megabytes for large projects.
//
// Implementation: read contents before [PROLOG_END], parse it as JSON and transform source paths.
// All rest contents will be passed directly from [input].
companion object {
internal const val PROLOG_END = "],\"sourcesContent\":"
const val UNSUPPORTED_FORMAT_MESSAGE =
"Unsupported format. Contents should starts with `{\"version\":3,\"file\":\"...\",\"sources\":[...],\"sourcesContent\":...`"
private val log = LoggerFactory.getLogger("kotlin")
}
private var wasReadFirst = false
private val prologLimit = 0xfffff
// buffer with transformed prolog, that wil be emitted first
private lateinit var bufferWriter: StringWriter
private lateinit var bufferJsonWriter: JsonWriter
private val buffer: StringBuffer get() = bufferWriter.buffer
private var bufferReadPos = 0
private val bufferAvailable get() = buffer.length - bufferReadPos
private var inputEof = false
lateinit var srcSourceRoot: String
lateinit var targetSourceRoot: String
private fun maybeReadFirst() {
if (!wasReadFirst) {
wasReadFirst = true
readFirst()
}
}
private fun readFirst() {
// read 1Kb chunks from [input] until [PROLOG_END] will be found
val jsonString = StringBuilder()
val readBuffer = CharArray(1024)
var lastRead: Int
var jsonPrologPos: Int
while (true) {
lastRead = input.read(readBuffer)
if (lastRead == -1) {
inputEof = true
writeBackUnsupported(jsonString, "$UNSUPPORTED_FORMAT_MESSAGE. \"sourcesContent\" or \"sources\" not found")
return
}
// Try find PROLOG_END. Note the case when prolog contents is splitted between reads.
// Like, one buffer ends with `],"sourc`, and the other starts with `esContent"`
val prevEnd = jsonString.length
jsonString.append(readBuffer, 0, lastRead)
jsonPrologPos = jsonString.indexOf(PROLOG_END, prevEnd - PROLOG_END.length)
if (jsonPrologPos == -1) {
if (jsonString.length + lastRead > prologLimit) {
writeBackUnsupported(jsonString, "Too many sources or format is not supported")
return
}
} else break
}
// create StringWriter to write transformed prolog and contents that was read after PROLOG_END
bufferWriter = StringWriter(jsonString.length)
bufferJsonWriter = JsonWriter(bufferWriter)
// parse json in prolog and write it back to bufferJsonWriter with transformed source paths
val json = JsonReader(StringReader(jsonString.toString()))
try {
json.beginObject()
bufferJsonWriter.beginObject()
reading@ while (true) {
val token = json.peek()
check(token == JsonToken.NAME) { "JSON key expected, but $token found" }
val key = json.nextName()
when (key) {
"sources" -> {
json.beginArray()
bufferJsonWriter.name("sources").beginArray()
while (json.peek() != JsonToken.END_ARRAY) {
val path = json.nextString()
bufferJsonWriter.value(transformString(path))
}
json.endArray()
}
"version" -> bufferJsonWriter.name(key).value(json.nextInt())
"file" -> bufferJsonWriter.name(key).value(json.nextString())
"sourcesContent" -> break@reading
else -> throw IllegalStateException("Unknown key \"$key\"")
}
}
// leave bufferJsonWriter unclosed
// push back contents that was read after PROLOG_END
bufferWriter.append(jsonString.substring(jsonPrologPos))
} catch (e: IllegalStateException) {
writeBackUnsupported(jsonString, json, e.message!!)
} catch (e: MalformedJsonException) {
writeBackUnsupported(jsonString, json, "Malformed JSON")
}
}
private fun writeBackUnsupported(jsonString: StringBuilder, reader: JsonReader, message: String) =
writeBackUnsupported(
jsonString,
"$UNSUPPORTED_FORMAT_MESSAGE. $message at ${reader.toString().replace("JsonReader at ", "")} in `$jsonString"
)
private fun writeBackUnsupported(jsonString: StringBuilder, reason: String) =
writeBackUnsupported(jsonString.toString(), reason)
private fun writeBackUnsupported(jsonString: String, reason: String) {
warnUnsupported(reason)
bufferWriter = StringWriter(jsonString.length)
bufferWriter.append(jsonString)
}
protected open fun warnUnsupported(reason: String) {
log.warn("Cannot rewrite paths in JavaScript source maps: $reason")
}
private fun transformString(value: String): String =
File(srcSourceRoot).resolve(value).canonicalFile.relativeToOrSelf(File(targetSourceRoot)).path
override fun read(): Int {
maybeReadFirst()
if (bufferAvailable == 0) {
if (inputEof) return -1
val read = input.read()
if (read == -1) {
inputEof = true
return -1
} else {
return read
}
}
return buffer[bufferReadPos++].toInt()
}
override fun read(dest: CharArray, initialDestOffset: Int, n: Int): Int {
maybeReadFirst()
var todo = n
var destOffset = initialDestOffset
while (todo > 0) {
if (bufferAvailable == 0) {
if (inputEof) return if (n == todo) -1 else n - todo
val read = input.read(dest, destOffset, todo)
if (read == -1) {
inputEof = true
return n - todo
} else {
return read + (n - todo)
}
}
val toRead = Math.min(todo, bufferAvailable)
buffer.getChars(bufferReadPos, bufferReadPos + toRead, dest, destOffset)
bufferReadPos += toRead
destOffset += toRead
todo -= toRead
}
return n - todo
}
override fun skip(n: Long): Long {
maybeReadFirst()
var todo = n.toInt()
while (todo > 0) {
if (bufferAvailable == 0) {
if (inputEof) return n - todo
val read = input.skip(todo.toLong())
if (read == 0L && todo != 0) {
inputEof = true
return n - todo
} else {
return read + (n - todo)
}
}
val toRead = Math.min(todo, bufferAvailable)
bufferReadPos += toRead
todo -= toRead
}
return n - todo
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.targets.js.internal.RewriteSourceMapFilterReader
import java.io.File
open class KotlinJsNodeModulesTask : DefaultTask() {
@@ -34,17 +35,29 @@ open class KotlinJsNodeModulesTask : DefaultTask() {
isKotlinJsRuntimeFile(fileTreeElement.file)
}
sync.eachFile {
if (it.name.endsWith(".js.map")) {
it.filter(
mapOf(
"srcSourceRoot" to it.file.parentFile,
"targetSourceRoot" to nodeModulesDir
),
RewriteSourceMapFilterReader::class.java
)
}
}
sync.into(nodeModulesDir)
}
}
}
private val File.isZip
get() = isFile && name.endsWith(".jar")
get() = isFile && (name.endsWith(".jar") || name.endsWith(".zip"))
internal fun isKotlinJsRuntimeFile(file: File): Boolean {
if (!file.isFile) return false
val name = file.name
return (name.endsWith(".js") && !name.endsWith(".meta.js"))
|| name.endsWith(".js.map")
|| name.endsWith(".js.map")
}
@@ -1,55 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
const val kotlinTestNodeJsRunnerJs = "kotlin-test-nodejs-runner.js"
internal val Project.extractedKotlinTestNodeJsRunner: File
get() = project.buildDir.resolve("kotlin/$kotlinTestNodeJsRunnerJs")
internal val Project.kotlinNodeJsTestRuntimeExtractTask
get() = project.locateOrRegisterTask<KotlinNodeJsTestRuntimeExtractTask>(
"kotlinNodeJsTestRuntimeExtract"
) { task ->
task.destination = extractedKotlinTestNodeJsRunner
}
open class KotlinNodeJsTestRuntimeExtractTask : DefaultTask() {
@Input
public var resourceName: String = "/$kotlinTestNodeJsRunnerJs"
@OutputFile
@SkipWhenEmpty
public lateinit var destination: File
@TaskAction
fun copyRuntime() {
val testsRuntime = javaClass.getResourceAsStream(resourceName)
?: error("Cannot find `$resourceName` in resources")
check(destination.parentFile.exists() || destination.parentFile.mkdirs()) {
"Cannot create directory ${destination.parentFile}"
}
Files.copy(
testsRuntime,
destination.toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
@@ -38,14 +38,14 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
var excludes = mutableSetOf<String>()
@InputDirectory
var nodeModulesDir: File? = null
lateinit var nodeModulesDir: File
@Input
@SkipWhenEmpty
var nodeModulesToLoad: Set<String> = setOf()
@InputFile
lateinit var testRuntimeNodeModule: File
@Input
lateinit var testRuntimeNodeModules: Collection<String>
@Suppress("UnstableApiUsage")
private val filterExt: DefaultTestFilter
@@ -69,6 +69,9 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
val nodeJsWorkingDirCanonicalPath: String
@Input get() = nodeJsProcessOptions.workingDir.canonicalPath
@Input
var debug: Boolean = false
fun nodeJs(options: ProcessForkOptions.() -> Unit) {
options(nodeJsProcessOptions)
}
@@ -77,7 +80,13 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
val extendedForkOptions = DefaultProcessForkOptions(fileResolver)
nodeJsProcessOptions.copyTo(extendedForkOptions)
extendedForkOptions.environment.addPath("NODE_PATH", nodeModulesDir!!.canonicalPath)
extendedForkOptions.environment.addPath("NODE_PATH", nodeModulesDir.canonicalPath)
val nodeJsArgs = mutableListOf<String>()
if (debug) {
nodeJsArgs.add("--inspect-brk")
}
val cliArgs = KotlinNodeJsTestRunnerCliArgs(
nodeModulesToLoad.toList(),
@@ -98,7 +107,12 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
return TCServiceMessagesTestExecutionSpec(
extendedForkOptions,
listOf(testRuntimeNodeModule.absolutePath) + cliArgs.toList(),
nodeJsArgs +
testRuntimeNodeModules
.map { nodeModulesDir.resolve(it) }
.filter { it.exists() }
.map { it.absolutePath } +
cliArgs.toList(),
clientSettings
)
}
@@ -0,0 +1,172 @@
package org.jetbrains.kotlin.gradle.org.jetbrains.kotlin.gradle.targets.js.internal
import org.jetbrains.kotlin.gradle.targets.js.internal.RewriteSourceMapFilterReader
import org.junit.Assert.assertEquals
import org.junit.Test
import java.io.Reader
import java.io.StringReader
class RewriteSourceMapFilterReaderTest {
@Test
fun testShort() {
// input json should fit in buffer (1024)
doTest(1)
}
@Test
fun testLong() {
doTest(100)
}
@Test
fun testVeryLong() {
doTest(1000)
}
@Test
fun testPrologSplitByReads() {
// Test the case when prolog contents is splitted between reads.
// Like, one buffer ends with `],"sourc`, and the other starts with `esContent"`
val prolog = sample("", "").substringBefore(RewriteSourceMapFilterReader.PROLOG_END)
doTest(1, addToProlog = "-".repeat(1024 - prolog.length - "],\"sourc".length))
}
private fun sample(mappings: String, addToProlog: String): String {
//language=JSON
return """{"version":3,"file":"single-platform${addToProlog}.js","sources":["../../../../src/main/kotlin/main.kt"],"sourcesContent":[null],"names":[],"mappings":"$mappings"}"""
}
private fun doTest(repeatMappings: Int, addToProlog: String = "") {
val mappings0 =
";;;;;;;;;;;;;;;;;;;;;;;;;IAQc,c;EAAA,C;;IAQc,O;IACJ,W;EAAA,C;;IAFA,aAAE,wBAAF,kBAA4B,gCAA5B," +
"C;IAGJ,W;EAAA,C;;IAJA,uBAAI,yBAAJ,C;IAKJ,W;EAAA,C;;IANA,wBAAK,kBAAL,C;IAOJ,W;EAAA,C;;IATR," +
"QACqC,KAAb,WAAhB,oBAAgB,CAAa,UAAK,WAAL,CADrC,C;EAWJ,C;;;;;;;;;"
val mappings = mappings0.repeat(repeatMappings)
val filter = RewriteSourceMapFilterReader(
StringReader(sample(mappings, addToProlog)),
"/root/build/classes/kotlin/test/",
"/root/build/test_node_modules/"
)
assertEquals(
//language=JSON
"""{"version":3,"file":"single-platform${addToProlog}.js","sources":["../../src/main/kotlin/main.kt"],"sourcesContent":[null],"names":[],"mappings":"$mappings"}""",
filter.readText()
)
}
@Test
fun testUnsupportedUnderfindProlog() {
val filter =
RewriteSourceMapFilterReaderMock(
StringReader(
//language=JSON
"""{"version":3,"file":"single-platform.js","sources":["../../../../src/main/kotlin/main.kt"],"names":[],"mappings":""}"""
),
"/root/build/classes/kotlin/test/",
"/root/build/test_node_modules/"
)
assertEquals(
//language=JSON
"""{"version":3,"file":"single-platform.js","sources":["../../../../src/main/kotlin/main.kt"],"names":[],"mappings":""}""",
filter.readText()
)
assertEquals(
"Unsupported format. Contents should starts with `{\"version\":3,\"file\":\"...\",\"sources\":[...],\"sourcesContent\":...`. \"sourcesContent\" or \"sources\" not found",
filter.warning
)
}
@Test
fun testUnsupportedPrologSize() {
val repeat = "\"../../../../src/main/kotlin/main.kt\",".repeat(0xfffff / 35)
val filter =
RewriteSourceMapFilterReaderMock(
StringReader(
//language=JSON
"""{"version":3,"file":"single-platform.js","sources":[$repeat],"sourcesContent":[null],"names":[],"mappings":""}"""
),
"/root/build/classes/kotlin/test/",
"/root/build/test_node_modules/"
)
assertEquals(
//language=JSON
"""{"version":3,"file":"single-platform.js","sources":[$repeat],"sourcesContent":[null],"names":[],"mappings":""}""",
filter.readText()
)
assertEquals("Too many sources or format is not supported", filter.warning)
}
@Test
fun testUnsupportedFormat() {
val filter =
RewriteSourceMapFilterReaderMock(
StringReader(
//language=JSON
"""{"file":"single-platform.js","version1":3,"sources":["../../../../src/main/kotlin/main.kt"],"sourcesContent":[null],"names":[],"mappings":""}"""
),
"/root/build/classes/kotlin/test/",
"/root/build/test_node_modules/"
)
assertEquals(
//language=JSON
"""{"file":"single-platform.js","version1":3,"sources":["../../../../src/main/kotlin/main.kt"],"sourcesContent":[null],"names":[],"mappings":""}""",
filter.readText()
)
assertEquals(
"Unsupported format. Contents should starts with `{\"version\":3,\"file\":\"...\",\"sources\":[...],\"sourcesContent\":...`. Unknown key \"version1\" at line 1 column 40 path \$.version1 in `{\"file\":\"single-platform.js\",\"version1\":3,\"sources\":[\"../../../../src/main/kotlin/main.kt\"],\"sourcesContent\":[null],\"names\":[],\"mappings\":\"\"}",
filter.warning
)
}
@Test
fun testInvalidJson() {
val filter =
RewriteSourceMapFilterReaderMock(
StringReader("{:)],\"sourcesContent\":[null]}"),
"/root/build/classes/kotlin/test/",
"/root/build/test_node_modules/"
)
assertEquals("{:)],\"sourcesContent\":[null]}", filter.readText())
assertEquals(
"Unsupported format. Contents should starts with `{\"version\":3,\"file\":\"...\",\"sources\":[...],\"sourcesContent\":...`. Malformed JSON at line 1 column 3 path \$. in `{:)],\"sourcesContent\":[null]}",
filter.warning
)
}
class RewriteSourceMapFilterReaderMock(input: Reader, srcSourceRoot: String, targetSourceRoot: String) :
RewriteSourceMapFilterReader(input) {
init {
setProperties(this, srcSourceRoot, targetSourceRoot)
}
var warning: String? = null
override fun warnUnsupported(reason: String) {
warning = reason
}
}
}
private fun RewriteSourceMapFilterReader(
input: Reader,
srcSourceRoot: String,
targetSourceRoot: String
) = RewriteSourceMapFilterReader(input).also {
setProperties(it, srcSourceRoot, targetSourceRoot)
}
private fun setProperties(
it: RewriteSourceMapFilterReader,
srcSourceRoot: String,
targetSourceRoot: String
) {
it.srcSourceRoot = srcSourceRoot
it.targetSourceRoot = targetSourceRoot
}
@@ -1,10 +1,27 @@
import com.moowork.gradle.node.yarn.YarnTask
description = "Simple Kotlin/JS tests runner with TeamCity reporter"
plugins {
id("base")
id("com.moowork.node") version "1.2.0"
}
val default = configurations.getByName(Dependency.DEFAULT_CONFIGURATION)
val archives = configurations.getByName(Dependency.ARCHIVES_CONFIGURATION)
default.extendsFrom(archives)
plugins.apply("maven")
convention.getPlugin(MavenPluginConvention::class.java).also {
it.conf2ScopeMappings.addMapping(MavenPlugin.RUNTIME_PRIORITY, archives, Conf2ScopeMappingContainer.RUNTIME)
}
dependencies {
archives(project(":kotlin-test:kotlin-test-js"))
}
node {
version = "11.9.0"
download = true
@@ -25,25 +42,43 @@ tasks {
setWorkingDir(projectDir)
args = listOf("build")
inputs.dir(projectDir.resolve("src"))
outputs.file(projectDir.resolve("lib/kotlin-test-nodejs-runner.js"))
inputs.dir("src")
inputs.files(
"cli.ts",
"nodejs-source-map-support.js",
"package.json",
"rollup.config.js",
"tsconfig.json",
"yarn.lock"
)
outputs.dir("lib")
}
create<Delete>("cleanYarn") {
group = "build"
delete = setOf(
projectDir.resolve("node_modules"),
projectDir.resolve("lib"),
projectDir.resolve(".rpt2_cache")
"node_modules",
"lib",
".rpt2_cache"
)
}
getByName("clean").dependsOn("cleanYarn")
}
val jar = tasks.create<Jar>("jar") {
dependsOn("yarnBuild")
from(projectDir.resolve("lib"))
}
artifacts {
add("archives", projectDir.resolve("lib/kotlin-test-nodejs-runner.js")) {
builtBy("yarnBuild")
add(
"archives",
jar.archiveFile.get().asFile
) {
builtBy(jar)
}
}
}
publish()
@@ -0,0 +1 @@
require('source-map-support').install();
@@ -14,7 +14,8 @@
"build": "rimraf lib/* && rollup -c rollup.config.js"
},
"dependencies": {
"@types/node": "^10.12.21"
"@types/node": "^10.12.21",
"source-map-support": "^0.5.11"
},
"devDependencies": {
"copyfiles": "^2.1.0",
@@ -11,49 +11,66 @@ export default [
output: {
file: 'lib/kotlin-test-nodejs-runner.js',
format: 'cjs',
banner: '#!/usr/bin/env node'
banner: '#!/usr/bin/env node',
sourcemap: true
},
plugins: [
nodeResolve({
jsnext: true,
main: true
}),
jsnext: true,
main: true
}),
commonjs(),
typescript({
tsconfig: "tsconfig.json"
}),
tsconfig: "tsconfig.json"
}),
uglify({
sourcemap: true,
compress: {
// hoist_funs: true,
// hoist_vars: true,
toplevel: true,
unsafe: true,
dead_code: true,
global_defs: {
DEBUG: false,
VERSION: pckg.version,
BIN: Object.keys(pckg.bin)[0],
DESCRIPTION: pckg.description
}
},
mangle: {
properties: {
keep_quoted: true,
reserved: [
"argv", "hrtime",
"kotlin_test", "kotlin", "setAdapter", "setAssertHook_4duqou$",
"suite", "test",
"stack"
]
},
toplevel: true,
},
// output: {
// beautify: true
// }
}),
// sourceMaps()
sourcemap: true,
compress: {
// hoist_funs: true,
// hoist_vars: true,
toplevel: true,
unsafe: true,
dead_code: true,
global_defs: {
DEBUG: false,
VERSION: pckg.version,
BIN: Object.keys(pckg.bin)[0],
DESCRIPTION: pckg.description
}
},
mangle: {
properties: {
keep_quoted: true,
reserved: [
"argv", "hrtime",
"kotlin_test", "kotlin", "setAdapter", "setAssertHook_4duqou$",
"suite", "test",
"stack"
]
},
toplevel: true,
}
})
]
},
{
input: './nodejs-source-map-support.js',
external: ['path', 'fs', 'module'],
output: {
file: 'lib/kotlin-nodejs-source-map-support.js',
format: 'cjs',
sourcemap: true
},
plugins: [
nodeResolve({
jsnext: true,
main: true
}),
commonjs(),
uglify({
compress: true,
sourcemap: true
})
]
}
]
@@ -2,10 +2,8 @@
"compilerOptions": {
"target": "es5",
"module": "ESNext",
// "declaration": true,
// "outDir": "./lib",
"strict": true,
// "sourceMap": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"inlineSourceMap": true
},
@@ -94,6 +94,11 @@ braces@^1.8.2:
preserve "^0.2.0"
repeat-element "^1.1.2"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
builtin-modules@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.0.0.tgz#1e587d44b006620d90286cc7a9238bbc6129cab1"
@@ -889,12 +894,20 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.5.11:
version "0.5.11"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2"
integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
source-map@~0.6.1:
source-map@^0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==