Add optional `srcs` and `deps` arguments to `compile_ts` so that it can be invoked from any rule and not just a rule like ts_library where the srcs and deps are part of ctx.attr. Behavior is same as before if these arguments are not provided.

PiperOrigin-RevId: 209596020
diff --git a/internal/common/compilation.bzl b/internal/common/compilation.bzl
index 75d3c64..65b34d6 100644
--- a/internal/common/compilation.bzl
+++ b/internal/common/compilation.bzl
@@ -59,8 +59,11 @@
 }
 
 # TODO(plf): Enforce this at analysis time.
-def assert_js_or_typescript_deps(ctx):
-    for dep in ctx.attr.deps:
+def assert_js_or_typescript_deps(ctx, deps = None):
+    # `deps` args is optinal for backward compat.
+    # Fallback to `ctx.attr.deps`.
+    deps = deps or ctx.attr.deps
+    for dep in deps:
         if not hasattr(dep, "typescript") and not hasattr(dep, "js"):
             fail(
                 ("%s is neither a TypeScript nor a JS producing rule." % dep.label) +
@@ -71,7 +74,7 @@
                 "also proto_library and some others).\n",
             )
 
-def _collect_dep_declarations(ctx):
+def _collect_dep_declarations(ctx, deps):
     """Collects .d.ts files from typescript and javascript dependencies.
 
     Args:
@@ -90,7 +93,7 @@
     # .d.ts files whose types tsickle will not emit (used for ts_declaration(generate_externs=False).
     type_blacklisted_declarations = depset()
 
-    for dep in ctx.attr.deps + getattr(ctx.attr, "_helpers", []):
+    for dep in deps + getattr(ctx.attr, "_helpers", []):
         if hasattr(dep, "typescript"):
             direct_deps_declarations += dep.typescript.declarations
             transitive_deps_declarations += dep.typescript.transitive_declarations
@@ -105,12 +108,13 @@
         type_blacklisted = type_blacklisted_declarations,
     )
 
-def _outputs(ctx, label):
+def _outputs(ctx, label, srcs_files = []):
     """Returns closure js, devmode js, and .d.ts output files.
 
     Args:
       ctx: ctx.
       label: Label. package label.
+      srcs_files: File list. sources files list.
 
     Returns:
       A struct of file lists for different output types.
@@ -123,7 +127,7 @@
     closure_js_files = []
     devmode_js_files = []
     declaration_files = []
-    for input_file in ctx.files.srcs:
+    for input_file in srcs_files:
         is_dts = input_file.short_path.endswith(".d.ts")
         if is_dts and not create_shim_files:
             continue
@@ -145,6 +149,8 @@
 def compile_ts(
         ctx,
         is_library,
+        srcs = None,
+        deps = None,
         compile_action = None,
         devmode_compile_action = None,
         jsx_factory = None,
@@ -157,6 +163,8 @@
     Args:
       ctx: ctx.
       is_library: boolean. False if only compiling .dts files.
+      srcs: label list. Explicit list of sources to be used instead of ctx.attr.srcs.
+      deps: label list. Explicit list of deps to be used instead of ctx.attr.deps.
       compile_action: function. Creates the compilation action.
       devmode_compile_action: function. Creates the compilation action
         for devmode.
@@ -167,16 +175,19 @@
     Returns:
       struct that will be returned by the rule implementation.
     """
-    assert_js_or_typescript_deps(ctx)
 
     ### Collect srcs and outputs.
-    srcs = ctx.files.srcs
+    srcs = srcs or ctx.attr.srcs
+    deps = deps or ctx.attr.deps
+    srcs_files = [f for t in srcs for f in t.files]
     src_declarations = []  # d.ts found in inputs.
     tsickle_externs = []  # externs.js generated by tsickle, if any.
     has_sources = False
 
     # Validate the user inputs.
-    for src in ctx.attr.srcs:
+    assert_js_or_typescript_deps(ctx, deps)
+
+    for src in srcs:
         if src.label.package != ctx.label.package:
             # Sources can be in sub-folders, but not in sub-packages.
             fail("Sources must be in the same package as the ts_library rule, " +
@@ -191,7 +202,7 @@
                 src_declarations += [f]
                 continue
 
-    outs = outputs(ctx, ctx.label)
+    outs = outputs(ctx, ctx.label, srcs_files)
     transpiled_closure_js = outs.closure_js
     transpiled_devmode_js = outs.devmode_js
     gen_declarations = outs.declarations
@@ -200,11 +211,11 @@
         # Note: setting this variable controls whether tsickle is run at all.
         tsickle_externs = [ctx.new_file(ctx.label.name + ".externs.js")]
 
-    dep_declarations = _collect_dep_declarations(ctx)
+    dep_declarations = _collect_dep_declarations(ctx, deps)
     input_declarations = dep_declarations.transitive + src_declarations
     type_blacklisted_declarations = dep_declarations.type_blacklisted
     if not is_library and not ctx.attr.generate_externs:
-        type_blacklisted_declarations += ctx.files.srcs
+        type_blacklisted_declarations += srcs_files
 
     # The list of output files. These are the files that are always built
     # (including e.g. if you "blaze build :the_target" directly).
@@ -221,14 +232,14 @@
     if "TYPESCRIPT_PERF_TRACE_TARGET" in ctx.var:
         perf_trace = str(ctx.label) == ctx.var["TYPESCRIPT_PERF_TRACE_TARGET"]
 
-    compilation_inputs = input_declarations + srcs
+    compilation_inputs = input_declarations + srcs_files
     tsickle_externs_path = tsickle_externs[0] if tsickle_externs else None
 
     # Calculate allowed dependencies for strict deps enforcement.
     allowed_deps = depset()
 
     # A target's sources may depend on each other,
-    allowed_deps += srcs[:]
+    allowed_deps += srcs_files[:]
 
     # or on a .d.ts from a direct dependency
     allowed_deps += dep_declarations.direct
@@ -236,7 +247,7 @@
     tsconfig_es6 = tsc_wrapped_tsconfig(
         ctx,
         compilation_inputs,
-        srcs,
+        srcs_files,
         jsx_factory = jsx_factory,
         tsickle_externs = tsickle_externs_path,
         type_blacklisted_declarations = type_blacklisted_declarations,
@@ -295,7 +306,7 @@
         tsconfig_es5 = tsc_wrapped_tsconfig(
             ctx,
             compilation_inputs,
-            srcs,
+            srcs_files,
             jsx_factory = jsx_factory,
             devmode_manifest = devmode_manifest.path,
             allowed_deps = allowed_deps,
@@ -354,10 +365,10 @@
     declarations = depset()
     declarations += gen_declarations
     declarations += src_declarations
-    if not srcs:
+    if not srcs_files:
         # Re-export sources from deps.
         # TODO(b/30018387): introduce an "exports" attribute.
-        for dep in ctx.attr.deps:
+        for dep in deps:
             if hasattr(dep, "typescript"):
                 declarations += dep.typescript.declarations
     files += declarations
@@ -370,7 +381,7 @@
 
     transitive_es5_sources = depset()
     transitive_es6_sources = depset()
-    for dep in ctx.attr.deps:
+    for dep in deps:
         if hasattr(dep, "typescript"):
             transitive_es5_sources = depset(transitive = [
                 transitive_es5_sources,