blob: 8af987ed8c8e4630a6db6fb57f2e5915f91936b7 [file] [log] [blame]
# Copyright 2017 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.
"""TypeScript rules.
"""
# pylint: disable=unused-argument
# pylint: disable=missing-docstring
load(":common/compilation.bzl", "compile_ts")
load(":executables.bzl", "get_tsc", "get_node")
load(":common/json_marshal.bzl", "json_marshal")
load(":common/tsconfig.bzl", "create_tsconfig")
load(":common/module_mappings.bzl", "module_mappings_aspect")
def _compile_action(ctx, inputs, outputs, config_file_path):
externs_files = []
non_externs_files = []
for output in outputs:
if output.basename.endswith(".externs.js"):
externs_files.append(output)
elif output.basename.endswith(".es5.MF"):
ctx.file_action(output, content="")
else:
non_externs_files.append(output)
# TODO(plf): For now we mock creation of files other than {name}.js.
for externs_file in externs_files:
ctx.file_action(output=externs_file, content="")
action_inputs = inputs
if ctx.file.tsconfig:
action_inputs += [ctx.file.tsconfig]
ctx.action(
inputs=action_inputs,
outputs=non_externs_files,
arguments=["-p", config_file_path],
executable=ctx.executable.tsc)
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
_compile_action(ctx, inputs, outputs, config_file_path)
def _tsc_wrapped_tsconfig(ctx,
files,
srcs,
devmode_manifest=None,
tsickle_externs=None,
type_blacklisted_declarations=[],
allowed_deps=set(),
jsx_factory=None,
ngc_out=[]):
variant = ""
if devmode_manifest: variant += "_es5"
tsconfig_json = ctx.new_file(ctx.label.name + variant + "_tsconfig.json")
# The location of tsconfig.json is interpreted as the root of the project
# when it is passed to the TS compiler with the `-p` option:
# https://www.typescriptlang.org/docs/handbook/tsconfig-json.html.
# Our tsconfig.json is in bazel-foo/bazel-out/local-fastbuild/bin/{package_path}
# because it's generated in the execution phase. However, our source files are in
# bazel-foo/ and therefore we need to strip some parent directories for each
# f.path.
workspace_path = "/".join([".."] * len(tsconfig_json.dirname.split("/")))
host_bin = "bazel-out/host/bin"
runfiles = ctx.executable.tsc.short_path + ".runfiles"
module_roots = {
"*": [
"/".join([host_bin, runfiles, "yarn/installed/node_modules/*"]),
],
# Workaround https://github.com/Microsoft/TypeScript/issues/15962
# Needed for Angular to build with Bazel.
# TODO(alexeagle): fix the bug upstream or find a better place for
# this workaround.
"zone.js": [
"/".join([host_bin, runfiles, "yarn/installed/node_modules/zone.js/dist/zone.js.d.ts"]),
]
}
config = create_tsconfig(ctx, files, srcs, tsconfig_json.dirname,
devmode_manifest=devmode_manifest,
module_roots=module_roots)
config["compilerOptions"].update({
"typeRoots": ["/".join([
workspace_path, host_bin, runfiles,
"yarn/installed/node_modules/@types"]
)],
})
# If the user gives a tsconfig attribute, the generated file should extend
# from the user's tsconfig.
# See https://github.com/Microsoft/TypeScript/issues/9876
# We subtract the ".json" from the end before handing to TypeScript because
# this gives extra error-checking.
if ctx.file.tsconfig:
config["extends"] = "{}/{}".format(workspace_path, ctx.file.tsconfig.path[:-5])
ctx.file_action(output=tsconfig_json, content=json_marshal(config))
return tsconfig_json
# ************ #
# ts_library #
# ************ #
def _ts_library_impl(ctx):
"""Implementation of ts_library.
Args:
ctx: the context.
Returns:
the struct returned by the call to compile_ts.
"""
ctx.file_action(
output = ctx.outputs._js_typings,
content = "")
return compile_ts(ctx, is_library=True, compile_action=_compile_action,
devmode_compile_action=_devmode_compile_action,
tsc_wrapped_tsconfig=_tsc_wrapped_tsconfig)
ts_library = rule(
_ts_library_impl,
attrs={
"srcs":
attr.label_list(
allow_files=FileType([
".ts",
".tsx",
]),
mandatory=True,),
"deps":
attr.label_list(aspects = [module_mappings_aspect]),
# Used to determine module mappings, see below.
"module_name": attr.string(),
"module_root": attr.string(),
# TODO(evanm): make this the default and remove the option.
"runtime":
attr.string(default="browser"),
# TODO(alexeagle): reconcile with google3: ts_library rules should
# be portable across internal/external, so we need this attribute
# internally as well.
"tsconfig":
attr.label(allow_files = True, single_file=True),
"_additional_d_ts":
attr.label_list(),
"tsc":
attr.label(
default=get_tsc(),
single_file=False,
allow_files=True,
executable=True,
cfg="host",),
"_node":
attr.label(
default=get_node(),
single_file=True,
allow_files=True,
executable=True,
cfg="host",),
"_node_modules": attr.label(default = Label("@yarn//installed:node_modules"))
},
fragments=["js"],
outputs={"_js_typings": "_%{name}_js_typings.d.ts"},)