b59f668a50
The idea is that we do no longer use `sourceMapBaseDirs` parameter of `compileKotlin2Js` task to remove prefix from source paths, but instead preserve the full paths relative to the output directory. This allows us to avoid duplicate file names and to identify source files more reliably. Then, after sources have been embedded in the source map, we remove several relative prefixes from source paths.
381 lines
11 KiB
Groovy
381 lines
11 KiB
Groovy
plugins {
|
|
id "com.github.node-gradle.node" version "3.0.1"
|
|
}
|
|
|
|
description = 'Kotlin Standard Library for JS'
|
|
|
|
apply plugin: 'kotlin-platform-js'
|
|
apply plugin: 'idea'
|
|
|
|
configurePublishing(project)
|
|
configureJavadocJar()
|
|
|
|
configurations {
|
|
sources
|
|
commonSources
|
|
distSources
|
|
distJs
|
|
distLibrary
|
|
}
|
|
|
|
def builtinsSrcDir = "${buildDir}/builtin-sources"
|
|
def builtinsSrcDir2 = "${buildDir}/builtin-sources-for-builtins"
|
|
def jsCommonDir = "${projectDir}/../js"
|
|
|
|
def builtinsDir = "${rootDir}/core/builtins"
|
|
|
|
def jsSrcDir = "src"
|
|
def jsCommonSrcDir = "${jsCommonDir}/src"
|
|
def jsTestSrcDir = "test"
|
|
def jsCommonTestSrcDir = "${jsCommonDir}/test"
|
|
|
|
def jsSrcJsDir = "${jsSrcDir}/js"
|
|
def jsOutputFileName = "${buildDir}/classes/kotlin.js"
|
|
def jsOutputMapFileName = "${jsOutputFileName}.map"
|
|
def jsOutputMetaFileName = "${buildDir}/classes/kotlin.meta.js"
|
|
|
|
def kotlinTestJsOutputFile = "${project(':kotlin-test:kotlin-test-js').buildDir}/classes/main/kotlin-test.js"
|
|
|
|
// TODO: take from sourcesets' outputs
|
|
def jsTestOutputFile = "${buildDir}/classes/kotlin/test/kotlin-stdlib-js_test.js"
|
|
def kotlinTestJsTestOutputFile = "${project(':kotlin-test:kotlin-test-js').buildDir}/classes/kotlin/test/kotlin-test-js_test.js"
|
|
|
|
sourceSets {
|
|
builtins {
|
|
kotlin {
|
|
srcDir builtinsSrcDir2
|
|
srcDir "${jsCommonDir}/runtime"
|
|
srcDir 'runtime'
|
|
}
|
|
}
|
|
|
|
main {
|
|
kotlin {
|
|
srcDir builtinsSrcDir
|
|
srcDir jsCommonSrcDir
|
|
srcDir jsSrcDir
|
|
}
|
|
}
|
|
|
|
test {
|
|
kotlin {
|
|
srcDir jsTestSrcDir
|
|
srcDir jsCommonTestSrcDir
|
|
}
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
expectedBy project(":kotlin-stdlib-common")
|
|
commonSources project(path: ":kotlin-stdlib-common", configuration: "sources")
|
|
testCompile project(':kotlin-test:kotlin-test-js')
|
|
}
|
|
|
|
task prepareComparableSource(type: Copy) {
|
|
def fs = services.get(FileSystemOperations)
|
|
doFirst {
|
|
fs.delete {
|
|
delete builtinsSrcDir2
|
|
}
|
|
}
|
|
from("${builtinsDir}/native/kotlin") {
|
|
include "Comparable.kt"
|
|
}
|
|
into builtinsSrcDir2
|
|
}
|
|
|
|
task prepareBuiltinsSources(type: Copy) {
|
|
def fs = services.get(FileSystemOperations)
|
|
doFirst {
|
|
fs.delete {
|
|
delete builtinsSrcDir
|
|
}
|
|
}
|
|
from("${builtinsDir}/native/kotlin") {
|
|
include "Iterator.kt"
|
|
include "Collections.kt"
|
|
include "CharSequence.kt"
|
|
include "Annotation.kt"
|
|
}
|
|
from("${builtinsDir}/src/kotlin/") {
|
|
include "annotation/Annotations.kt"
|
|
include "Function.kt"
|
|
include "Iterators.kt"
|
|
include "Range.kt"
|
|
include "Progressions.kt"
|
|
include "ProgressionIterators.kt"
|
|
include "Ranges.kt"
|
|
include "internal/InternalAnnotations.kt"
|
|
include "internal/progressionUtil.kt"
|
|
include "Unit.kt"
|
|
}
|
|
into builtinsSrcDir
|
|
}
|
|
|
|
tasks.withType(org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile) {
|
|
kotlinOptions {
|
|
main = "noCall"
|
|
moduleKind = "commonjs"
|
|
freeCompilerArgs = [
|
|
"-version",
|
|
"-Xallow-kotlin-package",
|
|
"-Xallow-result-return-type"
|
|
]
|
|
}
|
|
}
|
|
|
|
compileBuiltinsKotlin2Js {
|
|
dependsOn prepareComparableSource
|
|
kotlinOptions {
|
|
metaInfo = false
|
|
outputFile = "${buildDir}/classes/builtins/kotlin.js"
|
|
sourceMap = true
|
|
sourceMapPrefix = "./"
|
|
}
|
|
}
|
|
|
|
compileKotlin2Js {
|
|
dependsOn prepareBuiltinsSources
|
|
kotlinOptions {
|
|
outputFile = "${buildDir}/classes/main/kotlin.js"
|
|
sourceMap = true
|
|
freeCompilerArgs += [
|
|
"-Xopt-in=kotlin.RequiresOptIn",
|
|
"-Xopt-in=kotlin.ExperimentalMultiplatform",
|
|
"-Xopt-in=kotlin.contracts.ExperimentalContracts",
|
|
"-Xinline-classes"
|
|
]
|
|
}
|
|
}
|
|
|
|
compileTestKotlin2Js {
|
|
kotlinOptions {
|
|
moduleKind = "umd"
|
|
freeCompilerArgs += [
|
|
"-Xopt-in=kotlin.RequiresOptIn",
|
|
"-Xopt-in=kotlin.ExperimentalUnsignedTypes",
|
|
"-Xopt-in=kotlin.ExperimentalStdlibApi",
|
|
]
|
|
}
|
|
}
|
|
|
|
task compileJs(type: NoDebugJavaExec) {
|
|
dependsOn compileBuiltinsKotlin2Js, compileKotlin2Js
|
|
inputs.files(compileBuiltinsKotlin2Js.outputs.files).withPathSensitivity(PathSensitivity.RELATIVE)
|
|
inputs.files(compileKotlin2Js.outputs.files).withPathSensitivity(PathSensitivity.RELATIVE)
|
|
inputs.dir(jsSrcDir).withPathSensitivity(PathSensitivity.RELATIVE)
|
|
inputs.dir(jsCommonSrcDir).withPathSensitivity(PathSensitivity.RELATIVE)
|
|
|
|
outputs.file(jsOutputFileName)
|
|
outputs.file(jsOutputMapFileName)
|
|
outputs.file(jsOutputMetaFileName)
|
|
outputs.cacheIf { true }
|
|
|
|
def inputFiles = fileTree(jsSrcJsDir) {
|
|
include '**/*.js'
|
|
}
|
|
|
|
main = "org.jetbrains.kotlin.cli.js.internal.JSStdlibLinker"
|
|
|
|
// local variables for configuration cache work
|
|
def rootDir = rootDir
|
|
def projectDir = projectDir
|
|
|
|
def compileBuiltinsKotlin2JsFiles = compileBuiltinsKotlin2Js.outputs.files
|
|
def compileKotlin2JsFiles = compileKotlin2Js.outputs.files
|
|
doFirst {
|
|
args = [jsOutputFileName, rootDir, "$jsSrcDir/wrapper.js"] + inputFiles.collect { it.path }.sort() +
|
|
(compileBuiltinsKotlin2JsFiles.collect { it.path }.sort() +
|
|
compileKotlin2JsFiles.collect { it.path }.sort()).findAll {
|
|
it.endsWith(".js") && !it.endsWith(".meta.js")
|
|
}
|
|
}
|
|
classpath = configurations.kotlinCompilerClasspath
|
|
|
|
def sourceMapFile = file(jsOutputMapFileName)
|
|
def jsOutputMetaFile = file(jsOutputMetaFileName)
|
|
def compileMetaFile = file(compileKotlin2Js.outputFile.path.replaceAll('\\.js$', '.meta.js'))
|
|
def mainJsOutputDir = compileKotlin2Js.destinationDirectory
|
|
doLast {
|
|
ant.replaceregexp(
|
|
file: jsOutputFileName,
|
|
match: "module.exports,\\s*require\\([^)]+\\)",
|
|
replace: "",
|
|
byline: "true", encoding: "UTF-8")
|
|
ant.replaceregexp(
|
|
file: jsOutputFileName,
|
|
match: "function\\s*\\(_,\\s*Kotlin\\)",
|
|
replace: "function()",
|
|
byline: "true", encoding: "UTF-8")
|
|
ant.replaceregexp(
|
|
file: jsOutputFileName,
|
|
match: "return\\s+_;",
|
|
replace: "",
|
|
byline: "true", encoding: "UTF-8")
|
|
|
|
def sourceMap = new groovy.json.JsonSlurper().parseText(sourceMapFile.text)
|
|
|
|
def sourceMapSourcesBaseDirs = [mainJsOutputDir.get(), "${jsCommonDir}/runtime", projectDir, rootDir]
|
|
|
|
sourceMap.sourcesContent = sourceMap.sources.collect { sourceName ->
|
|
def text = sourceMapSourcesBaseDirs.collect { new File("$it/$sourceName") }.find { it.exists() }?.text
|
|
if (text == null) logger.warn("Sources missing for file $sourceName")
|
|
text
|
|
}
|
|
|
|
def sourceMapBasePaths = [
|
|
"../../../../",
|
|
"../../../",
|
|
"../../",
|
|
"./",
|
|
"libraries/stdlib/js-v1/src/"
|
|
]
|
|
def shortPaths = sourceMap.sources.collect { sourcePath ->
|
|
def prefixToRemove = sourceMapBasePaths.find { basePath -> sourcePath.startsWith(basePath) }
|
|
if (prefixToRemove != null) sourcePath.substring(prefixToRemove.length()) else sourcePath
|
|
}
|
|
if (shortPaths.size != shortPaths.toUnique().size) {
|
|
logger.warn("Duplicate source file names found:\n${sourceMap.sources.toSorted().join("\n")}")
|
|
}
|
|
sourceMap.sources = shortPaths
|
|
|
|
sourceMapFile.text = groovy.json.JsonOutput.toJson(sourceMap)
|
|
|
|
jsOutputMetaFile.text = compileMetaFile.text
|
|
}
|
|
}
|
|
|
|
classes.dependsOn compileJs
|
|
|
|
|
|
jar {
|
|
enabled false
|
|
}
|
|
|
|
task libraryJarWithoutIr(type: Jar, dependsOn: compileJs) {
|
|
archiveClassifier = null
|
|
manifestAttributes(manifest, project, 'Main')
|
|
destinationDirectory = file("$buildDir/lib/dist")
|
|
|
|
// TODO: Use standard implementation title after js stdlib detector becomes more flexible (KT-17655)
|
|
Properties properties = new Properties()
|
|
new File("${rootDir}/resources/kotlinManifest.properties").withInputStream {
|
|
properties.load(it)
|
|
}
|
|
manifest.attributes 'Implementation-Title': properties."manifest.impl.title.kotlin.javascript.stdlib"
|
|
|
|
includeEmptyDirs false
|
|
duplicatesStrategy DuplicatesStrategy.EXCLUDE
|
|
from jsOutputFileName
|
|
from jsOutputMetaFileName
|
|
from "${jsOutputFileName}.map"
|
|
from sourceSets.main.output
|
|
filesMatching("*.*") { it.mode = 0b110100100 } // KTI-401
|
|
}
|
|
|
|
task libraryJarWithIr(type: Zip, dependsOn: libraryJarWithoutIr) {
|
|
archiveExtension = "jar"
|
|
destinationDirectory = file("$buildDir/libs")
|
|
|
|
duplicatesStrategy DuplicatesStrategy.FAIL
|
|
|
|
from zipTree(libraryJarWithoutIr.archiveFile)
|
|
dependsOn(":kotlin-stdlib-js-ir:compileKotlinJs")
|
|
from {
|
|
def irKlib = tasks.getByPath(":kotlin-stdlib-js-ir:compileKotlinJs")
|
|
fileTree(irKlib.outputs.files.first().path)
|
|
}
|
|
filesMatching("*.*") { it.mode = 0b110100100 } // KTI-401
|
|
}
|
|
|
|
jar.dependsOn(libraryJarWithIr)
|
|
|
|
task sourcesJar(type: Jar, dependsOn: compileJs) {
|
|
archiveClassifier.set('sources')
|
|
includeEmptyDirs false
|
|
duplicatesStrategy = DuplicatesStrategy.FAIL
|
|
from("${builtinsDir}/native/kotlin") {
|
|
into 'kotlin'
|
|
include 'Comparable.kt'
|
|
include 'Enum.kt'
|
|
}
|
|
from(sourceSets.main.allSource) {
|
|
into 'kotlin'
|
|
exclude '**/*.java'
|
|
exclude 'org.w3c/**'
|
|
exclude 'js/**'
|
|
}
|
|
from(sourceSets.main.allSource) {
|
|
include 'org.w3c/**'
|
|
}
|
|
}
|
|
|
|
task distSourcesJar(type: Jar) {
|
|
dependsOn(sourcesJar, configurations.commonSources)
|
|
destinationDirectory = file("$buildDir/lib/dist")
|
|
archiveClassifier.set('sources')
|
|
duplicatesStrategy = DuplicatesStrategy.FAIL
|
|
from zipTree(sourcesJar.outputs.files.singleFile)
|
|
|
|
from(zipTree(configurations.commonSources.singleFile)) {
|
|
it.includeEmptyDirs = false
|
|
exclude 'META-INF/*'
|
|
into 'common'
|
|
}
|
|
}
|
|
|
|
artifacts {
|
|
runtime libraryJarWithIr
|
|
publishedRuntime libraryJarWithIr
|
|
publishedRuntime sourcesJar
|
|
sources sourcesJar
|
|
distSources distSourcesJar
|
|
distLibrary libraryJarWithIr
|
|
|
|
compileJs.outputs.files.forEach { artifact ->
|
|
distJs(artifact) { builtBy(compileJs) }
|
|
}
|
|
}
|
|
|
|
node {
|
|
download = true
|
|
version = '12.18.0'
|
|
nodeProjectDir = buildDir
|
|
}
|
|
|
|
// Otherwise Node ignores nodeModulesDir
|
|
task deleteLegacyNodeModules(type: Delete) {
|
|
delete "$projectDir/node_modules"
|
|
}
|
|
|
|
task installMocha(type: NpmTask, dependsOn: [deleteLegacyNodeModules]) {
|
|
args = ['install', 'mocha@8.0.1']
|
|
}
|
|
|
|
task installTeamcityReporter(type: NpmTask, dependsOn: [deleteLegacyNodeModules]) {
|
|
args = ['install', 'mocha-teamcity-reporter@3.0.0']
|
|
}
|
|
|
|
task runMocha(type: NodeTask, dependsOn: [testClasses, installMocha, ':kotlin-test:kotlin-test-js:testClasses']) {
|
|
script = file("${buildDir}/node_modules/mocha/bin/mocha")
|
|
|
|
if (project.hasProperty("teamcity")) {
|
|
dependsOn installTeamcityReporter
|
|
args = ['--reporter', 'mocha-teamcity-reporter']
|
|
}
|
|
else {
|
|
args = ['--reporter', 'min']
|
|
}
|
|
|
|
args = args.get() + ['--timeout', '10s']
|
|
args = args.get() + [jsTestOutputFile, kotlinTestJsTestOutputFile]
|
|
|
|
execOverrides {
|
|
it.ignoreExitValue = rootProject.ignoreTestFailures
|
|
it.environment('NODE_PATH', [file(jsOutputFileName).parent, file(kotlinTestJsOutputFile).parent].join(File.pathSeparator))
|
|
it.workingDir = buildDir
|
|
}
|
|
}
|
|
|
|
test.dependsOn runMocha
|