From d738f4286553fba267ef0f413fef17ae21b66f9b Mon Sep 17 00:00:00 2001
From: Alex Eagle <eagle@post.harvard.edu>
Date: Sun, 22 Mar 2020 21:28:29 -0700
Subject: [PATCH] fix(typescript): declare the .tsbuildinfo output

this fixes a bug on Windows where Bazel deletes known outputs like .js
but then tsc doesn't write the .js file again on next action because
the tsbuildinfo file indicates it is up-to-date
---
 packages/typescript/src/internal/ts_project.bzl   | 13 ++++++++++---
 packages/typescript/test/ts_project/a/BUILD.bazel |  1 +
 packages/typescript/test/ts_project/b/BUILD.bazel |  2 ++
 packages/typescript/test/ts_project/c/BUILD.bazel |  1 +
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/packages/typescript/src/internal/ts_project.bzl b/packages/typescript/src/internal/ts_project.bzl
index 2cfed0a3d8..7503ea05b5 100644
--- a/packages/typescript/src/internal/ts_project.bzl
+++ b/packages/typescript/src/internal/ts_project.bzl
@@ -18,6 +18,7 @@ _ATTRS = {
 # NB: the macro `ts_project_macro` will set these outputs based on user
 # telling us which settings are enabled in the tsconfig for this project.
 _OUTPUTS = {
+    "buildinfo_out": attr.output(),
     "js_outs": attr.output_list(),
     "map_outs": attr.output_list(),
     "typing_maps_outs": attr.output_list(),
@@ -77,6 +78,8 @@ def _ts_project_impl(ctx):
     if ctx.attr.extends:
         inputs.extend(ctx.files.extends)
     outputs = ctx.outputs.js_outs + ctx.outputs.map_outs + ctx.outputs.typings_outs + ctx.outputs.typing_maps_outs
+    if ctx.outputs.buildinfo_out:
+        outputs.append(ctx.outputs.buildinfo_out)
 
     if len(outputs) == 0:
         return []
@@ -132,6 +135,7 @@ def ts_project_macro(
         declaration = True,
         source_map = False,
         declaration_map = False,
+        composite = False,
         emit_declaration_only = False,
         tsc = "@npm//typescript/bin:tsc",
         **kwargs):
@@ -196,14 +200,16 @@ def ts_project_macro(
 
             Must include any tsconfig files "chained" by extends clauses.
 
-        declaration: if the `declaration` or `composite` bit are set in the tsconfig.
+        declaration: if the `declaration` bit is set in the tsconfig.
             Instructs Bazel to expect a `.d.ts` output for each `.ts` source.
         source_map: if the `sourceMap` bit is set in the tsconfig.
             Instructs Bazel to expect a `.js.map` output for each `.ts` source.
         declaration_map: if the `declarationMap` bit is set in the tsconfig.
             Instructs Bazel to expect a `.d.ts.map` output for each `.ts` source.
+        composite: if the `composite` bit is set in the tsconfig.
+            Instructs Bazel to expect a `.tsbuildinfo` output and a `.d.ts` output for each `.ts` source.
         emit_declaration_only: if the `emitDeclarationOnly` bit is set in the tsconfig.
-            Instructs Bazel *not* to expect `.js` outputs for `.ts` sources.
+            Instructs Bazel *not* to expect `.js` or `.js.map` outputs for `.ts` sources.
     """
 
     if srcs == None:
@@ -220,8 +226,9 @@ def ts_project_macro(
         extends = extends,
         js_outs = _out_paths(srcs, ".js") if not emit_declaration_only else [],
         map_outs = _out_paths(srcs, ".js.map") if source_map and not emit_declaration_only else [],
-        typings_outs = _out_paths(srcs, ".d.ts") if declaration else [],
+        typings_outs = _out_paths(srcs, ".d.ts") if declaration or composite else [],
         typing_maps_outs = _out_paths(srcs, ".d.ts.map") if declaration_map else [],
+        buildinfo_out = tsconfig[:-5] + ".tsbuildinfo" if composite else None,
         tsc = tsc,
         **kwargs
     )
diff --git a/packages/typescript/test/ts_project/a/BUILD.bazel b/packages/typescript/test/ts_project/a/BUILD.bazel
index 1fe9a2ace4..ebbb07a282 100644
--- a/packages/typescript/test/ts_project/a/BUILD.bazel
+++ b/packages/typescript/test/ts_project/a/BUILD.bazel
@@ -1,6 +1,7 @@
 load("@npm_bazel_typescript//:index.bzl", "ts_project")
 
 ts_project(
+    composite = True,
     extends = ["//packages/typescript/test/ts_project:tsconfig-base.json"],
     source_map = True,
     visibility = ["//packages/typescript/test:__subpackages__"],
diff --git a/packages/typescript/test/ts_project/b/BUILD.bazel b/packages/typescript/test/ts_project/b/BUILD.bazel
index c32f3e286a..6f141bd59f 100644
--- a/packages/typescript/test/ts_project/b/BUILD.bazel
+++ b/packages/typescript/test/ts_project/b/BUILD.bazel
@@ -6,6 +6,7 @@ package(default_visibility = ["//packages/typescript/test:__subpackages__"])
 ts_project(
     name = "tsconfig",  # This will use ./tsconfig.json
     srcs = [":b.ts"],
+    composite = True,
     extends = ["//packages/typescript/test/ts_project:tsconfig-base.json"],
     deps = ["//packages/typescript/test/ts_project/a:tsconfig"],
 )
@@ -14,6 +15,7 @@ ts_project(
     name = "tsconfig-test",  # This will use ./tsconfig-test.json
     testonly = True,
     srcs = [":b.spec.ts"],
+    composite = True,
     extends = ["//packages/typescript/test/ts_project:tsconfig-base.json"],
     deps = [
         ":tsconfig",
diff --git a/packages/typescript/test/ts_project/c/BUILD.bazel b/packages/typescript/test/ts_project/c/BUILD.bazel
index 599069cc78..71b03bd5c2 100644
--- a/packages/typescript/test/ts_project/c/BUILD.bazel
+++ b/packages/typescript/test/ts_project/c/BUILD.bazel
@@ -3,6 +3,7 @@ load("@npm_bazel_typescript//:index.bzl", "ts_project")
 ts_project(
     name = "compile",
     srcs = [":c.ts"],
+    composite = True,
     extends = ["//packages/typescript/test/ts_project:tsconfig-base.json"],
     tsconfig = "tsconfig.json",
     deps = ["//packages/typescript/test/ts_project/b:tsconfig"],