js_import expanded, now compatible with node module conventions
diff --git a/.bazelproject b/.bazelproject
index 4dc8ce1..af125c4 100644
--- a/.bazelproject
+++ b/.bazelproject
@@ -14,6 +14,11 @@
directories:
# Add the directories you want added as source here
# By default, we've added your entire workspace ('.')
+ -examples/node/bazel-node
+ -examples/node/bazel-bin
+ -examples/node/bazel-genfiles
+ -examples/node/bazel-out
+ -examples/node/bazel-testlogs
.
targets:
diff --git a/examples/node/express/BUILD b/examples/node/express/BUILD
index ca38a89..9c1b022 100644
--- a/examples/node/express/BUILD
+++ b/examples/node/express/BUILD
@@ -25,7 +25,7 @@
kt_js_library(
name ="app",
srcs = [":App.kt"],
- deps = [":acme-routes"],
+ deps = [":acme-routes"]
)
# The binary demonstrates an express app composed of three modules. The modules can co-exist in the same directory.
diff --git a/examples/node/package.json b/examples/node/package.json
index 7ae63ad..4f1fe67 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -2,9 +2,7 @@
"name": "node_packages",
"version": "1.0.0",
"dependencies": {
- "express": "^4.16.3",
- "kotlin": "1.2.60",
- "kotlin-test": "1.2.60"
+ "express": "^4.16.3"
},
"devDependencies": {
"source-map-support": "^0.5.6"
diff --git a/examples/node/yarn.lock b/examples/node/yarn.lock
index 06dda37..e01d70c 100644
--- a/examples/node/yarn.lock
+++ b/examples/node/yarn.lock
@@ -171,16 +171,6 @@
version "1.8.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
-kotlin-test@1.2.60:
- version "1.2.60"
- resolved "https://registry.yarnpkg.com/kotlin-test/-/kotlin-test-1.2.60.tgz#e238c48740a1c9f1c036d3c3db04d40f47c934db"
- dependencies:
- kotlin "1.2.60"
-
-kotlin@1.2.60:
- version "1.2.60"
- resolved "https://registry.yarnpkg.com/kotlin/-/kotlin-1.2.60.tgz#3d7ec2328a0d46281e21b9d7cf5314032217b010"
-
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/js/Kotlin2JsTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/js/Kotlin2JsTaskExecutor.kt
index 630bd4b..028130b 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/js/Kotlin2JsTaskExecutor.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/js/Kotlin2JsTaskExecutor.kt
@@ -21,7 +21,6 @@
private val invoker: KotlinToolchain.K2JSCompilerInvoker
) {
fun execute(context: CompilationTaskContext, task: JsCompilationTask) {
- context.print(Paths.get(task.inputs.kotlinSourcesList[0]).toRealPath().toAbsolutePath().toString())
task.compile(context)
val jsPath = Paths.get(task.outputs.js)
diff --git a/kotlin/internal/defs.bzl b/kotlin/internal/defs.bzl
index cde4313..62690d5 100644
--- a/kotlin/internal/defs.bzl
+++ b/kotlin/internal/defs.bzl
@@ -26,12 +26,10 @@
},
)
-# TODO when kt_js_import is capable of unpacking the jars and making the js and js_map files available then uncomment
-# the fields below.
KtJsInfo = provider(
fields = {
- # "js": "The primary output of the library",
- # "js_map": "The map file for the library",
+ "js": "The primary output of the library",
+ "js_map": "The map file for the library",
"jar": "A jar of the library.",
"srcjar": "The jar containing the sources of the library",
},
diff --git a/kotlin/internal/js/BUILD b/kotlin/internal/js/BUILD
index 9c0f139..9f0a0ec 100644
--- a/kotlin/internal/js/BUILD
+++ b/kotlin/internal/js/BUILD
@@ -11,3 +11,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+
+py_binary(
+ name = "importer",
+ srcs = ["importer.py"],
+ visibility = ["//visibility:public"],
+)
diff --git a/kotlin/internal/js/impl.bzl b/kotlin/internal/js/impl.bzl
index d565ed6..46580fb 100644
--- a/kotlin/internal/js/impl.bzl
+++ b/kotlin/internal/js/impl.bzl
@@ -13,6 +13,7 @@
# limitations under the License.
load(
"//kotlin/internal:defs.bzl",
+ _KT_COMPILER_REPO = "KT_COMPILER_REPO",
_KtJsInfo = "KtJsInfo",
_TOOLCHAIN_TYPE = "TOOLCHAIN_TYPE",
)
@@ -55,6 +56,7 @@
[
"-source-map",
"-meta-info",
+ "-no-stdlib", # TODO remove this once the stdlib is not conveyed to node via the deps attribute.
"-module-kind",
ctx.attr.module_kind,
"-target",
@@ -93,29 +95,51 @@
return [
DefaultInfo(
files = depset([ctx.outputs.js, ctx.outputs.js_map]),
- runfiles = ctx.runfiles(files = [
- ctx.outputs.js,
- ctx.outputs.js_map,
- ]),
),
_KtJsInfo(
+ js = ctx.outputs.js,
+ js_map = ctx.outputs.js_map,
jar = ctx.outputs.jar,
srcjar = ctx.outputs.srcjar,
),
]
-# This is just a placeholder at the moment.
def kt_js_import_impl(ctx):
if len(ctx.files.jars) != 1:
fail("a single jar should be supplied, multiple jars not supported")
+ jar_file = ctx.files.jars[0]
- files = depset(ctx.files.jars)
+ # Lock the jar name to the label name -- only make an exception for the compiler repo.
+ if not (ctx.label.workspace_root.startswith("external/") and ctx.label.workspace_root.endswith(_KT_COMPILER_REPO)):
+ expected_basename = "%s.jar" % ctx.label.name
+ if not jar_file.basename == expected_basename:
+ fail("label name %s is not the same as the jar name %s" % (jar_file.basename, expected_basename))
+
+ args = ctx.actions.args()
+ args.add("--jar", jar_file)
+ args.add("--out", ctx.outputs.js)
+ args.add("--aux", ctx.outputs.js_map)
+
+ inputs, _, input_manifest = ctx.resolve_command(tools = [ctx.attr._importer])
+ ctx.actions.run(
+ inputs = inputs + [jar_file],
+ executable = ctx.executable._importer,
+ outputs = [
+ ctx.outputs.js,
+ ctx.outputs.js_map,
+ ],
+ arguments = [args],
+ input_manifests = input_manifest,
+ )
+
return [
DefaultInfo(
- files = files,
+ files = depset([ctx.outputs.js, ctx.outputs.js_map]),
),
_KtJsInfo(
- jar = ctx.attr.jars[0],
- srcjar = ctx.attr.srcjar,
+ js = ctx.outputs.js,
+ js_map = ctx.outputs.js_map,
+ jar = jar_file,
+ srcjar = ctx.files.srcjar[0],
),
]
diff --git a/kotlin/internal/js/importer.py b/kotlin/internal/js/importer.py
new file mode 100644
index 0000000..7e54d50
--- /dev/null
+++ b/kotlin/internal/js/importer.py
@@ -0,0 +1,64 @@
+# Copyright 2018 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import argparse
+import os
+import zipfile
+
+
+def _is_jar(jar):
+ if not os.path.exists(jar):
+ raise argparse.ArgumentTypeError("jar:{0} does not exist".format(jar))
+ else:
+ return zipfile.ZipFile(jar)
+
+
+def _extract_root_entry(jar, entry_path, touch=False):
+ """
+ Extracts a root entry from a jar. and write it to a path.
+
+ entry_path is absolute and the basename is used to extract the entry from the jar.
+
+ :param jar: The jar from which to make the extraction.
+ :param entry_path: An absolute file path to where the entry should be written.
+ :param touch: Should the file be touched if it was not found in the jar.
+ """
+ basename = os.path.basename(entry_path)
+ try:
+ jar.read(basename)
+ except Exception as ex:
+ if touch:
+ f = open(entry_path, 'a')
+ f.close()
+ return
+ else:
+ raise ex
+ jar.extract(basename, path=os.path.dirname(entry_path))
+
+
+def _main(p):
+ args = p.parse_args()
+ _extract_root_entry(args.jar, args.out)
+ for e in args.aux:
+ _extract_root_entry(args.jar, e, touch=True)
+
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument("--jar", type=_is_jar, required=True)
+parser.add_argument("--out", required=True, help="mandatory paths to files that should be extracted from the root")
+parser.add_argument(
+ "--aux", nargs="*",
+ help="""paths to files that should be extracted from the root, if the files do not exist they are touched.""")
+
+_main(parser)
diff --git a/kotlin/internal/js/js.bzl b/kotlin/internal/js/js.bzl
index d7bdcf3..7360ebb 100644
--- a/kotlin/internal/js/js.bzl
+++ b/kotlin/internal/js/js.bzl
@@ -13,6 +13,7 @@
# limitations under the License.
load(
"//kotlin/internal:defs.bzl",
+ _KT_COMPILER_REPO = "KT_COMPILER_REPO",
_KtJsInfo = "KtJsInfo",
_TOOLCHAIN_TYPE = "TOOLCHAIN_TYPE",
)
@@ -22,6 +23,30 @@
_kt_js_library_impl = "kt_js_library_impl",
)
+_JS_STDLIB_MAP = {
+ "kotlin-stdlib-js": "kotlin",
+ "kotlin-test-js": "kotlin-test",
+}
+
+# The macro, and the ones using it exist to ensure compatibility with the nodejs rules, the nodejs rules process the
+# attributes and not the providers. Ideally providers would be used so the rules can pass the information along without
+# having to have user facing attributes visible.
+# module_root: if the module_root is made settable then there is a possibility of collisions. Keeping it simple here.
+# module_name: The require statement generated by Kotlinc-js seems to be based on the name of the jar. Unlike the jvm
+# compiler, there is no 'module-name' flag available. So to keep things simple it's hard coded to the module name.
+def _lock_attrs(name, kwargs):
+ if native.repository_name().startswith("@") and native.repository_name().endswith(_KT_COMPILER_REPO):
+ name = _JS_STDLIB_MAP.get(name, default = name)
+ if kwargs.get("module_root") != None:
+ fail("The module_root is an internal attribute.")
+ else:
+ kwargs["module_root"] = name + ".js"
+ if kwargs.get("module_name") != None:
+ fail("module_name is an internal attribute.")
+ else:
+ kwargs["module_name"] = name
+ return kwargs
+
kt_js_library = rule(
attrs = {
"srcs": attr.label_list(
@@ -29,8 +54,20 @@
allow_files = [".kt"],
mandatory = True,
),
+ "data": attr.label_list(
+ allow_files = True,
+ default = [],
+ cfg = "data",
+ ),
"deps": attr.label_list(
doc = """A list of other kotlin JS libraries.""",
+ default = [],
+ allow_empty = True,
+ providers = [_KtJsInfo],
+ ),
+ "runtime_deps": attr.label_list(
+ doc = """A list of other kotlin JS libraries that should be available at runtime.""",
+ default = [],
allow_empty = True,
providers = [_KtJsInfo],
),
@@ -51,6 +88,11 @@
doc = "internal attribute",
mandatory = False,
),
+ "_toolchain": attr.label(
+ doc = """The Kotlin JS Runtime.""",
+ default = Label("@" + _KT_COMPILER_REPO + "//:kotlin-stdlib-js"),
+ cfg = "target",
+ ),
},
implementation = _kt_js_library_impl,
outputs = dict(
@@ -63,26 +105,13 @@
provides = [_KtJsInfo],
)
-# The macro exists to ensure compatibility with the nodejs rules, the nodejs rules process the attributes and not the
-# providers. Ideally providers would be used so the rules can pass the information along without having to have user
-# facing attributes visible.
-# module_root: if the module_root is made settable then there is a possibility of collisions. Keeping it simple here.
-# module_name: The require statement generated by Kotlinc-js seems to be based on the name of the jar. Unlike the jvm
-# compiler, there is no 'module-name' flag available. So to keep things simple it's hard coded to the module name.
def kt_js_library_macro(name, **kwargs):
- if kwargs.get("module_root") != None:
- fail("The module_root is an internal attribute.")
- else:
- kwargs["module_root"] = name + ".js"
+ kwargs = _lock_attrs(name, kwargs)
- if kwargs.get("module_name") != None:
- fail("module_name is an internal attribute.")
- else:
- kwargs["module_name"] = name
+ # TODO this is a runtime dep, it should be picked up from the _toolchain attr or from a provider.
+ kwargs["deps"] = kwargs.get("deps", []) + ["@" + _KT_COMPILER_REPO + "//:kotlin-stdlib-js"]
kt_js_library(name = name, **kwargs)
-# TODO for Node the kotlin dependencies have to be provided via node_modules. The correct approach is to unpack the
-# the jars and make the js and js.map files available to node (via the module_root and module_name attributes?).
kt_js_import = rule(
attrs = {
"jars": attr.label_list(
@@ -99,7 +128,29 @@
allow_files = [".jar"],
mandatory = False,
),
+ "module_name": attr.string(
+ doc = "internal attribute",
+ mandatory = False,
+ ),
+ "module_root": attr.string(
+ doc = "internal attriubte",
+ mandatory = False,
+ ),
+ "_importer": attr.label(
+ default = "//kotlin/internal/js:importer",
+ allow_files = True,
+ executable = True,
+ cfg = "host",
+ ),
},
+ outputs = dict(
+ js = "%{module_name}.js",
+ js_map = "%{module_name}.js.map",
+ ),
implementation = _kt_js_import_impl,
provides = [_KtJsInfo],
)
+
+def kt_js_import_macro(name, **kwargs):
+ kwargs = _lock_attrs(name, kwargs)
+ kt_js_import(name = name, **kwargs)
diff --git a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
index 315a242..9d11d95 100644
--- a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
+++ b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
@@ -82,7 +82,6 @@
visibility = ["//visibility:public"],
)
for art in [
- "jslib",
"test-js",
"stdlib-js",
]
diff --git a/kotlin/internal/toolchains.bzl b/kotlin/internal/toolchains.bzl
index a22cba6..1f37feb 100644
--- a/kotlin/internal/toolchains.bzl
+++ b/kotlin/internal/toolchains.bzl
@@ -56,7 +56,7 @@
runtime_jars = ctx.files.jvm_runtime,
use_ijar = False,
),
- js_stdlibs = ctx.files.js_stdlibs,
+ js_stdlibs = ctx.attr.js_stdlibs,
)
return [
platform_common.ToolchainInfo(**toolchain),
diff --git a/kotlin/kotlin.bzl b/kotlin/kotlin.bzl
index 09158d0..bdae1a8 100644
--- a/kotlin/kotlin.bzl
+++ b/kotlin/kotlin.bzl
@@ -32,8 +32,9 @@
)
load(
"//kotlin/internal/js:js.bzl",
- "kt_js_import",
+ _kt_js_import = "kt_js_import_macro",
_kt_js_library = "kt_js_library_macro",
)
kt_js_library = _kt_js_library
+kt_js_import = _kt_js_import