chore(6.0): remove typescript internals
diff --git a/.github/BUILD.bazel b/.github/BUILD.bazel
index f782e51..7960a3a 100644
--- a/.github/BUILD.bazel
+++ b/.github/BUILD.bazel
@@ -8,10 +8,6 @@
     # do not sort
     owners = [
         "//:OWNERS",
-        "//examples:OWNERS.examples_jest",
-        "//examples:OWNERS.examples_nestjs",
-        "//examples:OWNERS.examples_angular",
-        "//examples:OWNERS.examples_angular_bazel_architect",
     ],
 )
 
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2a25941..c5977d4 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,8 +2,4 @@
 # To update, run:
 #    yarn update-codeowners
 
-* @mattem @gregmagolan @alexeagle
-/examples/jest/** @mrmeku @alexeagle @gregmagolan @mattem
-/examples/nestjs/** @zachgrayio @zMotivat0r @rayman1104 @siberex @alexeagle @gregmagolan @mattem
-/examples/angular/** @alan-agius4 @jbedard @alexeagle @gregmagolan @mattem
-/examples/angular_bazel_architect/** @alan-agius4 @jbedard @alexeagle @gregmagolan @mattem
+* @mattem @gregmagolan @alexeagle @jbedard
diff --git a/docs/Built-ins.md b/docs/Built-ins.md
index 0a5da6f..ae9f91f 100755
--- a/docs/Built-ins.md
+++ b/docs/Built-ins.md
@@ -100,7 +100,6 @@
 ```python
 nodejs_binary(
     name = "bin",
-    data = [":main"]
     entry_point = ":main.js",
 )
 ```
@@ -566,8 +565,6 @@
     On Windows runfiles are off by default and must be enabled with the `--enable_runfiles` flag when
     using this feature.
 
-NB: `ts_project` does not support directory npm deps due to internal dependency on having all input sources files explicitly specified.
-
 For the `nodejs_binary` & `nodejs_test` `entry_point` attribute (which often needs to reference a file within
 an npm package) you can set the entry_point to a dict with a single entry, where the key corresponds to the directory
 label and the value corresponds to the path within that directory to the entry point, e.g.
@@ -1242,8 +1239,6 @@
     On Windows runfiles are off by default and must be enabled with the `--enable_runfiles` flag when
     using this feature.
 
-NB: `ts_project` does not support directory npm deps due to internal dependency on having all input sources files explicitly specified.
-
 For the `nodejs_binary` & `nodejs_test` `entry_point` attribute (which often needs to reference a file within
 an npm package) you can set the entry_point to a dict with a single entry, where the key corresponds to the directory
 label and the value corresponds to the path within that directory to the entry point, e.g.
@@ -1700,13 +1695,11 @@
     package_name = "@myco/mypkg",
     # Consumers might need fields like "main" or "typings"
     srcs = ["package.json"],
+    # The .js and .d.ts outputs from above will be part of the package
     data = glob(["*.js"]),
 )
 ```
 
-> `js_library` has some undocumented advanced features you can find in the source code or in our examples.
-> These should not be considered a public API and aren't subject to our usual support and semver guarantees.
-
 ### Outputs
 
 Like all Bazel rules it produces a default output by providing [DefaultInfo].
diff --git a/docs/Providers.md b/docs/Providers.md
index a083bd6..160798b 100755
--- a/docs/Providers.md
+++ b/docs/Providers.md
@@ -73,6 +73,7 @@
 
 JavaScript files whose module name is self-contained.
 
+For example named AMD/UMD or goog.module format.
 These outputs should be named "foo.umd.js"
 (note that renaming it from "foo.js" doesn't affect the module id)
 
diff --git a/packages/typescript/checked_in_ts_project.bzl b/internal/checked_in_tsc.bzl
similarity index 61%
rename from packages/typescript/checked_in_ts_project.bzl
rename to internal/checked_in_tsc.bzl
index 889f86a..1fa7e08 100644
--- a/packages/typescript/checked_in_ts_project.bzl
+++ b/internal/checked_in_tsc.bzl
@@ -1,23 +1,17 @@
-"checked_in_ts_project rule"
+"checked_in_tsc rule"
 
 load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")
-load("//packages/typescript:index.bzl", "ts_project")
+load("//internal:tsc.bzl", "tsc")
 
-def checked_in_ts_project(name, src, checked_in_js = None, tsconfig = None, **kwargs):
-    """
-    In rules_nodejs "builtin" package, we are creating the toolchain for building
-    tsc-wrapped and executing ts_project, so we cannot depend on them.
-    However, we still want to be able to write our tooling in TypeScript.
-    This macro lets us check in the resulting .js files, and still ensure that they are
-    compiled from the .ts by using a golden file test.
-    """
+def checked_in_tsc(name, src, checked_in_js = None, tsconfig = None, **kwargs):
+    """A tsc rule that also asserts that the generated JS is up-to-date."""
     if not checked_in_js:
         checked_in_js = src[:-3] + ".js"
 
     if tsconfig == None:
         tsconfig = "//:tsconfig.json"
 
-    ts_project(
+    tsc(
         name = name,
         srcs = [src],
         tsconfig = tsconfig,
diff --git a/internal/coverage/BUILD.bazel b/internal/coverage/BUILD.bazel
index 9da8434..8fe71e8 100644
--- a/internal/coverage/BUILD.bazel
+++ b/internal/coverage/BUILD.bazel
@@ -1,9 +1,9 @@
 load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
 
 # BEGIN-INTERNAL
-load("//packages/typescript:checked_in_ts_project.bzl", "checked_in_ts_project")
+load("//internal:checked_in_tsc.bzl", "checked_in_tsc")
 
-checked_in_ts_project(
+checked_in_tsc(
     name = "lcov_merger_js_lib",
     src = "lcov_merger.ts",
     checked_in_js = "lcov_merger-js.js",
diff --git a/internal/linker/BUILD.bazel b/internal/linker/BUILD.bazel
index 80580b8..ba03158 100644
--- a/internal/linker/BUILD.bazel
+++ b/internal/linker/BUILD.bazel
@@ -2,14 +2,14 @@
 
 # BEGIN-INTERNAL
 load("//:index.bzl", "js_library")
-load("//packages/typescript:checked_in_ts_project.bzl", "checked_in_ts_project")
+load("//internal:checked_in_tsc.bzl", "checked_in_tsc")
 
 # We can't bootstrap the ts_library rule using the linker itself,
 # because the implementation of ts_library depends on the linker so that would be a cycle.
 # So we compile it to JS and check in the result as index.js.
 # To update index.js run:
 #   bazel run //internal/linker:linker_lib_check_compiled.update
-checked_in_ts_project(
+checked_in_tsc(
     name = "linker_lib",
     src = "link_node_modules.ts",
     checked_in_js = "index.js",
diff --git a/internal/linker/test/BUILD.bazel b/internal/linker/test/BUILD.bazel
index d462258..af700e4 100644
--- a/internal/linker/test/BUILD.bazel
+++ b/internal/linker/test/BUILD.bazel
@@ -1,6 +1,6 @@
-load("//packages/typescript:index.bzl", "ts_project")
+load("//internal:tsc.bzl", "tsc")
 
-ts_project(
+tsc(
     name = "test_lib",
     srcs = glob(["*.ts"]),
     deps = [
diff --git a/internal/linker/test/multi_linker/BUILD.bazel b/internal/linker/test/multi_linker/BUILD.bazel
index a34b875..bba4692 100644
--- a/internal/linker/test/multi_linker/BUILD.bazel
+++ b/internal/linker/test/multi_linker/BUILD.bazel
@@ -1,6 +1,6 @@
-load("//packages/typescript:checked_in_ts_project.bzl", "checked_in_ts_project")
+load("//internal:checked_in_tsc.bzl", "checked_in_tsc")
 
-checked_in_ts_project(
+checked_in_tsc(
     name = "checked_in_test",
     src = "test.ts",
     checked_in_js = "checked_in_test.js",
diff --git a/internal/npm_install/BUILD.bazel b/internal/npm_install/BUILD.bazel
index 54c7dcd..07d5a2f 100644
--- a/internal/npm_install/BUILD.bazel
+++ b/internal/npm_install/BUILD.bazel
@@ -3,12 +3,12 @@
 
 # BEGIN-INTERNAL
 # avoid leaking a ts dependency
-load("//packages/typescript:checked_in_ts_project.bzl", "checked_in_ts_project")
+load("//internal:checked_in_tsc.bzl", "checked_in_tsc")
 
 # Using checked in ts library like the linker
 # To update index.js run:
 #   bazel run //internal/npm_install:compile_generate_build_file_check_compiled.update
-checked_in_ts_project(
+checked_in_tsc(
     name = "compile_generate_build_file",
     src = "generate_build_file.ts",
     checked_in_js = "index.js",
diff --git a/internal/npm_install/npm_install.bzl b/internal/npm_install/npm_install.bzl
index cad4ab2..beeadc4 100644
--- a/internal/npm_install/npm_install.bzl
+++ b/internal/npm_install/npm_install.bzl
@@ -155,7 +155,7 @@
 @npm//target
 ```
 
-that can be referenced as `data` or `deps` by other rules such as `nodejs_binary` and `ts_project`
+that can be referenced as `data` or `deps` by other rules such as `nodejs_binary`
 and can be required as `@scope/target` and `target` with standard node_modules resolution at runtime,
 
 ```
@@ -168,16 +168,6 @@
         "@npm//other/dep"
     ],
 )
-
-ts_project(
-    name = "test",
-    srcs = [...],
-    deps = [
-        "@npm//@scope/target",
-        "@npm//target"
-        "@npm//other/dep"
-    ],
-)
 ```
 """,
     ),
diff --git a/internal/pkg_npm/pkg_npm.bzl b/internal/pkg_npm/pkg_npm.bzl
index 89165da..d67b091 100644
--- a/internal/pkg_npm/pkg_npm.bzl
+++ b/internal/pkg_npm/pkg_npm.bzl
@@ -96,7 +96,7 @@
 # Used in angular/angular /packages/bazel/src/ng_package/ng_package.bzl
 PKG_NPM_ATTRS = {
     "deps": attr.label_list(
-        doc = """Other targets which produce files that should be included in the package`""",
+        doc = """Other targets which produce files that should be included in the package""",
         allow_files = True,
     ),
     "nested_packages": attr.label_list(
diff --git a/internal/pkg_npm/test/pkg_npm.spec.js b/internal/pkg_npm/test/pkg_npm.spec.js
index a44e64e..28c6554 100644
--- a/internal/pkg_npm/test/pkg_npm.spec.js
+++ b/internal/pkg_npm/test/pkg_npm.spec.js
@@ -33,7 +33,7 @@
   it('copies files from other packages', () => {
     expect(readFromPkg('dependent_file')).toEqual('dependent_file content');
   });
-  it('copies js files from ts_project', () => {
+  it('copies js files from tsc', () => {
     expect(readFromPkg('foo.js')).toContain('exports.a = \'\';');
   });
   it('copies data dependencies', () => {
diff --git a/packages/typescript/index.bzl b/internal/tsc.bzl
similarity index 65%
rename from packages/typescript/index.bzl
rename to internal/tsc.bzl
index 84f2193..ab8165e 100644
--- a/packages/typescript/index.bzl
+++ b/internal/tsc.bzl
@@ -1,10 +1,10 @@
-load("@npm//typescript:index.bzl", "tsc")
+load("@npm//typescript:index.bzl", _tsc = "tsc")
 
-# Basic wrapper around tsc to replace ts_project()
-def ts_project(name, srcs, deps = [], data = [], tsconfig = "//:tsconfig.json", **kwargs):
+# Basic wrapper around tsc to replace tsc()
+def tsc(name, srcs, deps = [], data = [], tsconfig = "//:tsconfig.json", **kwargs):
     outs = [s.replace(".ts", ".js") for s in srcs] + [s.replace(".ts", ".d.ts") for s in srcs]
 
-    tsc(
+    _tsc(
         name = name,
         args = [
             "-p",
diff --git a/nodejs/private/BUILD.bazel b/nodejs/private/BUILD.bazel
index 28bf7fd..a839aa9 100644
--- a/nodejs/private/BUILD.bazel
+++ b/nodejs/private/BUILD.bazel
@@ -1,7 +1,5 @@
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 
-exports_files(["ts_project_options_validator.js"])
-
 filegroup(
     name = "package_contents",
     srcs = glob(["*"]) + [
diff --git a/nodejs/private/ts_config.bzl b/nodejs/private/ts_config.bzl
deleted file mode 100644
index c16ad74..0000000
--- a/nodejs/private/ts_config.bzl
+++ /dev/null
@@ -1,152 +0,0 @@
-# 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.
-
-"tsconfig.json files using extends"
-
-load(":ts_lib.bzl", _lib = "lib")
-
-TsConfigInfo = provider(
-    doc = """Provides TypeScript configuration, in the form of a tsconfig.json file
-        along with any transitively referenced tsconfig.json files chained by the
-        "extends" feature""",
-    fields = {
-        "deps": "all tsconfig.json files needed to configure TypeScript",
-    },
-)
-
-def _ts_config_impl(ctx):
-    files = depset([ctx.file.src])
-    transitive_deps = []
-    for dep in ctx.attr.deps:
-        if TsConfigInfo in dep:
-            transitive_deps.append(dep[TsConfigInfo].deps)
-    transitive_deps.append(depset(ctx.files.deps))
-    return [
-        DefaultInfo(files = files),
-        TsConfigInfo(deps = depset([ctx.file.src], transitive = transitive_deps)),
-    ]
-
-ts_config = rule(
-    implementation = _ts_config_impl,
-    attrs = {
-        "deps": attr.label_list(
-            doc = """Additional tsconfig.json files referenced via extends""",
-            allow_files = True,
-        ),
-        "src": attr.label(
-            doc = """The tsconfig.json file passed to the TypeScript compiler""",
-            allow_single_file = True,
-            mandatory = True,
-        ),
-    },
-    doc = """Allows a tsconfig.json file to extend another file.
-
-Normally, you just give a single `tsconfig.json` file as the tsconfig attribute
-of a `ts_project` rule. However, if your `tsconfig.json` uses the `extends`
-feature from TypeScript, then the Bazel implementation needs to know about that
-extended configuration file as well, to pass them both to the TypeScript compiler.
-""",
-)
-
-def _join(*elements):
-    return "/".join([f for f in elements if f])
-
-def _relative_path(tsconfig, dest):
-    relative_to = tsconfig.dirname
-    if dest.is_source:
-        # Calculate a relative path from the directory where we're writing the tsconfig
-        # back to the sources root
-        workspace_root = "/".join([".."] * len(relative_to.split("/")))
-        return _join(workspace_root, dest.path)
-
-    # Bazel guarantees that srcs are beneath the package directory, and we disallow
-    # tsconfig.json being generated with a "/" in the name.
-    # So we can calculate a relative path from e.g.
-    # bazel-out/darwin-fastbuild/bin/packages/typescript/test/ts_project/generated_tsconfig/gen_src
-    # to <generated file packages/typescript/test/ts_project/generated_tsconfig/gen_src/subdir/a.ts>
-    result = dest.path[len(relative_to) + 1:]
-    if not result.startswith("."):
-        result = "./" + result
-    return result
-
-def _filter_input_files(files, allow_js, resolve_json_module):
-    return [
-        f
-        for f in files
-        if _lib.is_ts_src(f.basename, allow_js) or _lib.is_json_src(f.basename, resolve_json_module)
-    ]
-
-def _write_tsconfig_rule(ctx):
-    # TODO: is it useful to expand Make variables in the content?
-    content = "\n".join(ctx.attr.content)
-    if ctx.attr.extends:
-        content = content.replace(
-            "__extends__",
-            _relative_path(ctx.outputs.out, ctx.file.extends),
-        )
-
-    filtered_files = _filter_input_files(ctx.files.files, ctx.attr.allow_js, ctx.attr.resolve_json_module)
-    if filtered_files:
-        content = content.replace(
-            "\"__files__\"",
-            str([_relative_path(ctx.outputs.out, f) for f in filtered_files]),
-        )
-    ctx.actions.write(
-        output = ctx.outputs.out,
-        content = content,
-    )
-    return [DefaultInfo(files = depset([ctx.outputs.out]))]
-
-write_tsconfig_rule = rule(
-    implementation = _write_tsconfig_rule,
-    attrs = {
-        "content": attr.string_list(),
-        "extends": attr.label(allow_single_file = True),
-        "files": attr.label_list(allow_files = True),
-        "out": attr.output(),
-        "allow_js": attr.bool(),
-        "resolve_json_module": attr.bool(),
-    },
-)
-
-# Syntax sugar around skylib's write_file
-def write_tsconfig(name, config, files, out, extends = None, allow_js = None, resolve_json_module = None):
-    """Wrapper around bazel_skylib's write_file which understands tsconfig paths
-
-    Args:
-        name: name of the resulting write_file rule
-        config: tsconfig dictionary
-        files: list of input .ts files to put in the files[] array
-        out: the file to write
-        extends: a label for a tsconfig.json file to extend from, if any
-    """
-    if out.find("/") >= 0:
-        fail("tsconfig should be generated in the package directory, to make relative pathing simple")
-
-    if extends:
-        config["extends"] = "__extends__"
-
-    amended_config = struct(
-        files = "__files__",
-        **config
-    )
-    write_tsconfig_rule(
-        name = name,
-        files = files,
-        extends = extends,
-        content = [json.encode(amended_config)],
-        out = out,
-        allow_js = allow_js,
-        resolve_json_module = resolve_json_module,
-    )
diff --git a/nodejs/private/ts_lib.bzl b/nodejs/private/ts_lib.bzl
deleted file mode 100644
index 32817b1..0000000
--- a/nodejs/private/ts_lib.bzl
+++ /dev/null
@@ -1,264 +0,0 @@
-"Utilities functions for selecting and filtering ts and other files"
-
-load("@rules_nodejs//nodejs/private/providers:declaration_info.bzl", "DeclarationInfo")
-
-ValidOptionsInfo = provider(
-    doc = "Internal: whether the validator ran successfully",
-    fields = {
-        "marker": """useless file that must be depended on to cause the validation action to run.
-        TODO: replace with https://docs.bazel.build/versions/main/skylark/rules.html#validation-actions""",
-    },
-)
-
-# Targets in deps must provide one or the other of these
-DEPS_PROVIDERS = [
-    [DeclarationInfo],
-    [ValidOptionsInfo],
-]
-
-# Attributes common to all TypeScript rules
-STD_ATTRS = {
-    "args": attr.string_list(
-        doc = "https://www.typescriptlang.org/docs/handbook/compiler-options.html",
-    ),
-    "data": attr.label_list(
-        doc = "Runtime dependencies to include in binaries/tests that depend on this TS code",
-        default = [],
-        allow_files = True,
-    ),
-    "declaration_dir": attr.string(
-        doc = "Always controlled by Bazel. https://www.typescriptlang.org/tsconfig#declarationDir",
-    ),
-    # Note, this is overridden by the @bazel/typescript implementation in build_bazel_rules_nodejs
-    # to add an aspect on the deps attribute.
-    "deps": attr.label_list(
-        doc = "Other targets which produce TypeScript typings",
-        providers = DEPS_PROVIDERS,
-    ),
-    "out_dir": attr.string(
-        doc = "Always controlled by Bazel. https://www.typescriptlang.org/tsconfig#outDir",
-    ),
-    "root_dir": attr.string(
-        doc = "Always controlled by Bazel. https://www.typescriptlang.org/tsconfig#rootDir",
-    ),
-    # NB: no restriction on extensions here, because tsc sometimes adds type-check support
-    # for more file kinds (like require('some.json')) and also
-    # if you swap out the `compiler` attribute (like with ngtsc)
-    # that compiler might allow more sources than tsc does.
-    "srcs": attr.label_list(
-        doc = "TypeScript source files",
-        allow_files = True,
-        mandatory = True,
-    ),
-    "supports_workers": attr.bool(
-        doc = "Whether the tsc compiler understands Bazel's persistent worker protocol",
-        default = False,
-    ),
-    "transpile": attr.bool(
-        doc = "whether tsc should be used to produce .js outputs",
-        default = True,
-    ),
-    "tsc": attr.label(
-        doc = "TypeScript compiler binary",
-        mandatory = True,
-        executable = True,
-        cfg = "exec",
-    ),
-    "tsconfig": attr.label(
-        doc = "tsconfig.json file, see https://www.typescriptlang.org/tsconfig",
-        mandatory = True,
-        allow_single_file = [".json"],
-    ),
-}
-
-# These attrs are shared between the validate and the ts_project rules
-# They simply mirror data from the compilerOptions block in tsconfig.json
-# so that Bazel can predict all of tsc's outputs.
-COMPILER_OPTION_ATTRS = {
-    "allow_js": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#allowJs",
-    ),
-    "composite": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#composite",
-    ),
-    "declaration": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#declaration",
-    ),
-    "declaration_map": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#declarationMap",
-    ),
-    "emit_declaration_only": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#emitDeclarationOnly",
-    ),
-    "extends": attr.label(
-        allow_files = [".json"],
-        doc = "https://www.typescriptlang.org/tsconfig#extends",
-    ),
-    "incremental": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#incremental",
-    ),
-    "preserve_jsx": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#jsx",
-    ),
-    "resolve_json_module": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#resolveJsonModule",
-    ),
-    "source_map": attr.bool(
-        doc = "https://www.typescriptlang.org/tsconfig#sourceMap",
-    ),
-}
-
-# tsc knows how to produce the following kinds of output files.
-# 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.
-OUTPUT_ATTRS = {
-    "buildinfo_out": attr.output(
-        doc = "Location in bazel-out where tsc will write a `.tsbuildinfo` file",
-    ),
-    "js_outs": attr.output_list(
-        doc = "Locations in bazel-out where tsc will write `.js` files",
-    ),
-    "map_outs": attr.output_list(
-        doc = "Locations in bazel-out where tsc will write `.js.map` files",
-    ),
-    "typing_maps_outs": attr.output_list(
-        doc = "Locations in bazel-out where tsc will write `.d.ts.map` files",
-    ),
-    "typings_outs": attr.output_list(
-        doc = "Locations in bazel-out where tsc will write `.d.ts` files",
-    ),
-}
-
-def _join(*elements):
-    segments = [f for f in elements if f]
-    if len(segments):
-        return "/".join(segments)
-    return "."
-
-def _strip_external(path):
-    return path[len("external/"):] if path.startswith("external/") else path
-
-def _relative_to_package(path, ctx):
-    for prefix in [ctx.bin_dir.path, ctx.label.workspace_name, ctx.label.package]:
-        prefix += "/"
-        path = _strip_external(path)
-        if path.startswith(prefix):
-            path = path[len(prefix):]
-    return path
-
-def _is_ts_src(src, allow_js):
-    if not src.endswith(".d.ts") and (src.endswith(".ts") or src.endswith(".tsx")):
-        return True
-    return allow_js and (src.endswith(".js") or src.endswith(".jsx"))
-
-def _is_json_src(src, resolve_json_module):
-    return resolve_json_module and src.endswith(".json")
-
-def _replace_ext(f, ext_map):
-    cur_ext = f[f.rindex("."):]
-    new_ext = ext_map.get(cur_ext)
-    if new_ext != None:
-        return new_ext
-    new_ext = ext_map.get("*")
-    if new_ext != None:
-        return new_ext
-    return None
-
-def _out_paths(srcs, out_dir, root_dir, allow_js, ext_map):
-    rootdir_replace_pattern = root_dir + "/" if root_dir else ""
-    outs = []
-    for f in srcs:
-        if _is_ts_src(f, allow_js):
-            out = _join(out_dir, f[:f.rindex(".")].replace(rootdir_replace_pattern, "", 1) + _replace_ext(f, ext_map))
-
-            # Don't declare outputs that collide with inputs
-            # for example, a.js -> a.js
-            if out != f:
-                outs.append(out)
-    return outs
-
-def _calculate_js_outs(srcs, out_dir, root_dir, allow_js, preserve_jsx, emit_declaration_only):
-    if emit_declaration_only:
-        return []
-
-    exts = {
-        "*": ".js",
-        ".jsx": ".jsx",
-        ".tsx": ".jsx",
-    } if preserve_jsx else {"*": ".js"}
-    return _out_paths(srcs, out_dir, root_dir, allow_js, exts)
-
-def _calculate_map_outs(srcs, out_dir, root_dir, source_map, preserve_jsx, emit_declaration_only):
-    if not source_map or emit_declaration_only:
-        return []
-
-    exts = {
-        "*": ".js.map",
-        ".tsx": ".jsx.map",
-    } if preserve_jsx else {"*": ".js.map"}
-    return _out_paths(srcs, out_dir, root_dir, False, exts)
-
-def _calculate_typings_outs(srcs, typings_out_dir, root_dir, declaration, composite, allow_js, include_srcs = True):
-    if not (declaration or composite):
-        return []
-    return _out_paths(srcs, typings_out_dir, root_dir, allow_js, {"*": ".d.ts"})
-
-def _calculate_typing_maps_outs(srcs, typings_out_dir, root_dir, declaration_map, allow_js):
-    if not declaration_map:
-        return []
-
-    exts = {"*": ".d.ts.map"}
-    return _out_paths(srcs, typings_out_dir, root_dir, allow_js, exts)
-
-def _calculate_root_dir(ctx):
-    some_generated_path = None
-    some_source_path = None
-    root_path = None
-
-    # Note we don't have access to the ts_project macro allow_js param here.
-    # For error-handling purposes, we can assume that any .js/.jsx
-    # input is meant to be in the rootDir alongside .ts/.tsx sources,
-    # whether the user meant for them to be sources or not.
-    # It's a non-breaking change to relax this constraint later, but would be
-    # a breaking change to restrict it further.
-    allow_js = True
-    for src in ctx.files.srcs:
-        if _is_ts_src(src.path, allow_js):
-            if src.is_source:
-                some_source_path = src.path
-            else:
-                some_generated_path = src.path
-                root_path = ctx.bin_dir.path
-
-    if some_source_path and some_generated_path:
-        fail("ERROR: %s srcs cannot be a mix of generated files and source files " % ctx.label +
-             "since this would prevent giving a single rootDir to the TypeScript compiler\n" +
-             "    found generated file %s and source file %s" %
-             (some_generated_path, some_source_path))
-
-    return _join(
-        root_path,
-        ctx.label.workspace_root,
-        ctx.label.package,
-        ctx.attr.root_dir,
-    )
-
-def _declare_outputs(ctx, paths):
-    return [
-        ctx.actions.declare_file(path)
-        for path in paths
-    ]
-
-lib = struct(
-    declare_outputs = _declare_outputs,
-    join = _join,
-    relative_to_package = _relative_to_package,
-    is_ts_src = _is_ts_src,
-    is_json_src = _is_json_src,
-    out_paths = _out_paths,
-    calculate_js_outs = _calculate_js_outs,
-    calculate_map_outs = _calculate_map_outs,
-    calculate_typings_outs = _calculate_typings_outs,
-    calculate_typing_maps_outs = _calculate_typing_maps_outs,
-    calculate_root_dir = _calculate_root_dir,
-)
diff --git a/nodejs/private/ts_project.bzl b/nodejs/private/ts_project.bzl
deleted file mode 100644
index a4b6767..0000000
--- a/nodejs/private/ts_project.bzl
+++ /dev/null
@@ -1,224 +0,0 @@
-"ts_project rule"
-
-load("@bazel_skylib//lib:dicts.bzl", "dicts")
-load("@rules_nodejs//nodejs/private/providers:declaration_info.bzl", "DeclarationInfo", "declaration_info")
-load("@rules_nodejs//nodejs/private/providers:js_providers.bzl", "js_module_info")
-load(":ts_lib.bzl", "COMPILER_OPTION_ATTRS", "OUTPUT_ATTRS", "STD_ATTRS", "ValidOptionsInfo", _lib = "lib")
-load(":ts_config.bzl", "TsConfigInfo")
-load(":ts_validate_options.bzl", _validate_lib = "lib")
-
-def _ts_project_impl(ctx, run_action = None, ExternalNpmPackageInfo = None):
-    """Creates the action which spawns `tsc`.
-
-    This function has two extra arguments that are particular to how it's called
-    within build_bazel_rules_nodejs and @bazel/typescript npm package.
-    Other TS rule implementations wouldn't need to pass these:
-
-    Args:
-        ctx: starlark rule execution context
-        run_action: used with the build_bazel_rules_nodejs linker, by default we use ctx.actions.run
-        ExternalNpmPackageInfo: a provider symbol specific to the build_bazel_rules_nodejs linker
-
-    Returns:
-        list of providers
-    """
-    srcs = [_lib.relative_to_package(src.path, ctx) for src in ctx.files.srcs]
-
-    # Recalculate outputs inside the rule implementation.
-    # The outs are first calculated in the macro in order to try to predetermine outputs so they can be declared as
-    # outputs on the rule. This provides the benefit of being able to reference an output file with a label.
-    # However, it is not possible to evaluate files in outputs of other rules such as filegroup, therefore the outs are
-    # recalculated here.
-    typings_out_dir = ctx.attr.declaration_dir or ctx.attr.out_dir
-    js_outs = _lib.declare_outputs(ctx, [] if not ctx.attr.transpile else _lib.calculate_js_outs(srcs, ctx.attr.out_dir, ctx.attr.root_dir, ctx.attr.allow_js, ctx.attr.preserve_jsx, ctx.attr.emit_declaration_only))
-    map_outs = _lib.declare_outputs(ctx, [] if not ctx.attr.transpile else _lib.calculate_map_outs(srcs, ctx.attr.out_dir, ctx.attr.root_dir, ctx.attr.source_map, ctx.attr.preserve_jsx, ctx.attr.emit_declaration_only))
-    typings_outs = _lib.declare_outputs(ctx, _lib.calculate_typings_outs(srcs, typings_out_dir, ctx.attr.root_dir, ctx.attr.declaration, ctx.attr.composite, ctx.attr.allow_js))
-    typing_maps_outs = _lib.declare_outputs(ctx, _lib.calculate_typing_maps_outs(srcs, typings_out_dir, ctx.attr.root_dir, ctx.attr.declaration_map, ctx.attr.allow_js))
-
-    arguments = ctx.actions.args()
-    execution_requirements = {}
-    progress_prefix = "Compiling TypeScript project"
-
-    if ctx.attr.supports_workers:
-        # Set to use a multiline param-file for worker mode
-        arguments.use_param_file("@%s", use_always = True)
-        arguments.set_param_file_format("multiline")
-        execution_requirements["supports-workers"] = "1"
-        execution_requirements["worker-key-mnemonic"] = "TsProject"
-        progress_prefix = "Compiling TypeScript project (worker mode)"
-
-    # Add user specified arguments *before* rule supplied arguments
-    arguments.add_all(ctx.attr.args)
-
-    arguments.add_all([
-        "--project",
-        ctx.file.tsconfig.path,
-        "--outDir",
-        _lib.join(ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package, ctx.attr.out_dir),
-        "--rootDir",
-        _lib.calculate_root_dir(ctx),
-    ])
-    if len(typings_outs) > 0:
-        declaration_dir = ctx.attr.declaration_dir if ctx.attr.declaration_dir else ctx.attr.out_dir
-        arguments.add_all([
-            "--declarationDir",
-            _lib.join(ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package, declaration_dir),
-        ])
-
-    # When users report problems, we can ask them to re-build with
-    # --define=VERBOSE_LOGS=1
-    # so anything that's useful to diagnose rule failures belongs here
-    if "VERBOSE_LOGS" in ctx.var.keys():
-        arguments.add_all([
-            # What files were in the ts.Program
-            "--listFiles",
-            # Did tsc write all outputs to the place we expect to find them?
-            "--listEmittedFiles",
-            # Why did module resolution fail?
-            "--traceResolution",
-            # Why was the build slow?
-            "--diagnostics",
-            "--extendedDiagnostics",
-        ])
-
-    transitive_inputs = []
-    inputs = ctx.files.srcs[:]
-    for dep in ctx.attr.deps:
-        if TsConfigInfo in dep:
-            transitive_inputs.append(dep[TsConfigInfo].deps)
-        if ExternalNpmPackageInfo != None and ExternalNpmPackageInfo in dep:
-            # TODO: we could maybe filter these to be tsconfig.json or *.d.ts only
-            # we don't expect tsc wants to read any other files from npm packages.
-            transitive_inputs.append(dep[ExternalNpmPackageInfo].sources)
-        if DeclarationInfo in dep:
-            transitive_inputs.append(dep[DeclarationInfo].transitive_declarations)
-        if ValidOptionsInfo in dep:
-            transitive_inputs.append(depset([dep[ValidOptionsInfo].marker]))
-
-    # Gather TsConfig info from both the direct (tsconfig) and indirect (extends) attribute
-    tsconfig_inputs = _validate_lib.tsconfig_inputs(ctx)
-    transitive_inputs.append(tsconfig_inputs)
-
-    # We do not try to predeclare json_outs, because their output locations generally conflict with their path in the source tree.
-    # (The exception is when out_dir is used, then the .json output is a different path than the input.)
-    # However tsc will copy .json srcs to the output tree so we want to declare these outputs to include along with .js Default outs
-    # NB: We don't have emit_declaration_only setting here, so use presence of any JS outputs as an equivalent.
-    # tsc will only produce .json if it also produces .js
-    if len(js_outs):
-        pkg_len = len(ctx.label.package) + 1 if len(ctx.label.package) else 0
-        rootdir_replace_pattern = ctx.attr.root_dir + "/" if ctx.attr.root_dir else ""
-        json_outs = _lib.declare_outputs(ctx, [
-            _lib.join(ctx.attr.out_dir, src.short_path[pkg_len:].replace(rootdir_replace_pattern, ""))
-            for src in ctx.files.srcs
-            if src.basename.endswith(".json") and src.is_source
-        ])
-    else:
-        json_outs = []
-
-    outputs = json_outs + js_outs + map_outs + typings_outs + typing_maps_outs
-    if ctx.outputs.buildinfo_out:
-        arguments.add_all([
-            "--tsBuildInfoFile",
-            ctx.outputs.buildinfo_out.path,
-        ])
-        outputs.append(ctx.outputs.buildinfo_out)
-    runtime_outputs = json_outs + js_outs + map_outs
-    typings_outputs = typings_outs + typing_maps_outs + [s for s in ctx.files.srcs if s.path.endswith(".d.ts")]
-
-    if not js_outs and not typings_outputs and not ctx.attr.deps:
-        label = "//{}:{}".format(ctx.label.package, ctx.label.name)
-        if ctx.attr.transpile:
-            no_outs_msg = """ts_project target %s is configured to produce no outputs.
-
-This might be because
-- you configured it with `noEmit`
-- the `srcs` are empty
-""" % label
-        else:
-            no_outs_msg = "ts_project target %s with custom transpiler needs `declaration = True`." % label
-        fail(no_outs_msg + """
-This is an error because Bazel does not run actions unless their outputs are needed for the requested targets to build.
-""")
-
-    if ctx.attr.transpile:
-        default_outputs_depset = depset(runtime_outputs) if len(runtime_outputs) else depset(typings_outputs)
-    else:
-        # We must avoid tsc writing any JS files in this case, as tsc was only run for typings, and some other
-        # action will try to write the JS files. We must avoid collisions where two actions write the same file.
-        arguments.add("--emitDeclarationOnly")
-
-        # We don't produce any DefaultInfo outputs in this case, because we avoid running the tsc action
-        # unless the DeclarationInfo is requested.
-        default_outputs_depset = depset([])
-
-    if len(outputs) > 0:
-        run_action_kwargs = {
-            "inputs": depset(inputs, transitive = transitive_inputs),
-            "arguments": [arguments],
-            "outputs": outputs,
-            "mnemonic": "TsProject",
-            "execution_requirements": execution_requirements,
-            "progress_message": "%s %s [tsc -p %s]" % (
-                progress_prefix,
-                ctx.label,
-                ctx.file.tsconfig.short_path,
-            ),
-        }
-        if run_action != None:
-            run_action(
-                ctx,
-                link_workspace_root = ctx.attr.link_workspace_root,
-                executable = "tsc",
-                **run_action_kwargs
-            )
-        else:
-            ctx.actions.run(
-                executable = ctx.executable.tsc,
-                **run_action_kwargs
-            )
-
-    providers = [
-        # DefaultInfo is what you see on the command-line for a built library,
-        # and determines what files are used by a simple non-provider-aware
-        # downstream library.
-        # Only the JavaScript outputs are intended for use in non-TS-aware
-        # dependents.
-        DefaultInfo(
-            files = default_outputs_depset,
-            runfiles = ctx.runfiles(
-                transitive_files = depset(ctx.files.data, transitive = [
-                    default_outputs_depset,
-                ]),
-                collect_default = True,
-            ),
-        ),
-        js_module_info(
-            sources = depset(runtime_outputs),
-            deps = ctx.attr.deps,
-        ),
-        TsConfigInfo(deps = depset(transitive = [tsconfig_inputs] + [
-            dep[TsConfigInfo].deps
-            for dep in ctx.attr.deps
-            if TsConfigInfo in dep
-        ])),
-        coverage_common.instrumented_files_info(
-            ctx,
-            source_attributes = ["srcs"],
-            dependency_attributes = ["deps"],
-            extensions = ["ts", "tsx"],
-        ),
-    ]
-
-    # Only provide DeclarationInfo if there are some typings.
-    # Improves error messaging if a ts_project is missing declaration = True
-    typings_in_deps = [d for d in ctx.attr.deps if DeclarationInfo in d]
-    if len(typings_outputs) or len(typings_in_deps):
-        providers.append(declaration_info(depset(typings_outputs), typings_in_deps))
-        providers.append(OutputGroupInfo(types = depset(typings_outputs)))
-
-    return providers
-
-ts_project = struct(
-    implementation = _ts_project_impl,
-    attrs = dicts.add(COMPILER_OPTION_ATTRS, STD_ATTRS, OUTPUT_ATTRS),
-)
diff --git a/nodejs/private/ts_project_options_validator.js b/nodejs/private/ts_project_options_validator.js
deleted file mode 100755
index 119b1b9..0000000
--- a/nodejs/private/ts_project_options_validator.js
+++ /dev/null
@@ -1,144 +0,0 @@
-"use strict";
-exports.__esModule = true;
-var path_1 = require("path");
-var ts = require("typescript");
-var diagnosticsHost = {
-    getCurrentDirectory: function () { return ts.sys.getCurrentDirectory(); },
-    getNewLine: function () { return ts.sys.newLine; },
-    // Print filenames including their relativeRoot, so they can be located on
-    // disk
-    getCanonicalFileName: function (f) { return f; }
-};
-function main(_a) {
-    var _b;
-    var tsconfigPath = _a[0], output = _a[1], target = _a[2], attrsStr = _a[3];
-    // The Bazel ts_project attributes were json-encoded
-    // (on Windows the quotes seem to be quoted wrong, so replace backslash with quotes :shrug:)
-    var attrs = JSON.parse(attrsStr.replace(/\\/g, '"'));
-    // Parse your typescript settings from the tsconfig
-    // This will understand the "extends" semantics.
-    var _c = ts.readConfigFile(tsconfigPath, ts.sys.readFile), config = _c.config, error = _c.error;
-    if (error)
-        throw new Error(tsconfigPath + ':' + ts.formatDiagnostic(error, diagnosticsHost));
-    var _d = ts.parseJsonConfigFileContent(config, ts.sys, path_1.dirname(tsconfigPath)), errors = _d.errors, options = _d.options;
-    // We don't pass the srcs to this action, so it can't know if the program has the right sources.
-    // Diagnostics look like
-    // error TS18002: The 'files' list in config file 'tsconfig.json' is empty.
-    // error TS18003: No inputs were found in config file 'tsconfig.json'. Specified 'include'...
-    var fatalErrors = errors.filter(function (e) { return e.code !== 18002 && e.code !== 18003; });
-    if (fatalErrors.length > 0)
-        throw new Error(tsconfigPath + ':' + ts.formatDiagnostics(fatalErrors, diagnosticsHost));
-    var failures = [];
-    var buildozerCmds = [];
-    function getTsOption(option) {
-        if (typeof (options[option]) === 'string') {
-            // Currently the only string-typed options are filepaths.
-            // TypeScript will resolve these to a project path
-            // so when echoing that back to the user, we need to reverse that resolution.
-            // First turn //path/to/pkg:tsconfig into path/to/pkg
-            var packageDir = target.substr(2, target.indexOf(':') - 2);
-            return path_1.relative(packageDir, options[option]);
-        }
-        return options[option];
-    }
-    function check(option, attr) {
-        attr = attr || option;
-        // treat compilerOptions undefined as false
-        var optionVal = getTsOption(option);
-        var match = optionVal === attrs[attr] ||
-            (optionVal === undefined && (attrs[attr] === false || attrs[attr] === ''));
-        if (!match) {
-            failures.push("attribute " + attr + "=" + attrs[attr] + " does not match compilerOptions." + option + "=" + optionVal);
-            if (typeof (optionVal) === 'boolean') {
-                buildozerCmds.push("set " + attr + " " + (optionVal ? 'True' : 'False'));
-            }
-            else if (typeof (optionVal) === 'string') {
-                buildozerCmds.push("set " + attr + " \"" + optionVal + "\"");
-            }
-            else if (optionVal === undefined) {
-                // nothing to sync
-            }
-            else {
-                throw new Error("cannot check option " + option + " of type " + typeof (option));
-            }
-        }
-    }
-    var jsxEmit = (_b = {},
-        _b[ts.JsxEmit.None] = 'none',
-        _b[ts.JsxEmit.Preserve] = 'preserve',
-        _b[ts.JsxEmit.React] = 'react',
-        _b[ts.JsxEmit.ReactNative] = 'react-native',
-        _b[ts.JsxEmit.ReactJSX] = 'react-jsx',
-        _b[ts.JsxEmit.ReactJSXDev] = 'react-jsx-dev',
-        _b);
-    function check_preserve_jsx() {
-        var attr = 'preserve_jsx';
-        var jsxVal = options['jsx'];
-        if ((jsxVal === ts.JsxEmit.Preserve) !== Boolean(attrs[attr])) {
-            failures.push("attribute " + attr + "=" + attrs[attr] + " does not match compilerOptions.jsx=" + jsxEmit[jsxVal]);
-            buildozerCmds.push("set " + attr + " " + (jsxVal === ts.JsxEmit.Preserve ? 'True' : 'False'));
-        }
-    }
-    if (options.noEmit) {
-        console.error("ERROR: ts_project rule " + target + " cannot be built because the 'noEmit' option is specified in the tsconfig.");
-        console.error('This is not compatible with ts_project, which always produces outputs.');
-        console.error('- If you mean to only typecheck the code, use the tsc_test rule instead.');
-        console.error('  (See the Alternatives section in the documentation.)');
-        console.error('- Otherwise, remove the noEmit option from tsconfig and try again.');
-        return 1;
-    }
-    // When there are dependencies on other ts_project targets, the tsconfig must be configured
-    // to help TypeScript resolve them.
-    if (attrs.has_local_deps) {
-        var rootDirsValid = true;
-        if (!options.rootDirs) {
-            console.error("ERROR: ts_project rule " + target + " is configured without rootDirs.");
-            rootDirsValid = false;
-        }
-        else if (!options.rootDirs.some(function (d) { return d.startsWith(process.env['BINDIR']); })) {
-            console.error("ERROR: ts_project rule " + target + " is missing a needed rootDir under " + process.env['BINDIR'] + ".");
-            console.error('Found only: ', options.rootDirs);
-            rootDirsValid = false;
-        }
-        if (!rootDirsValid) {
-            console.error('This makes it likely that TypeScript will be unable to resolve dependencies using relative import paths');
-            console.error("For example, if you 'import {} from ./foo', this expects to resolve foo.d.ts from Bazel's output tree");
-            console.error('and TypeScript only knows how to locate this when the rootDirs attribute includes that path.');
-            console.error('See the ts_project documentation: https://bazelbuild.github.io/rules_nodejs/TypeScript.html#ts_project');
-            return 1;
-        }
-    }
-    check('allowJs', 'allow_js');
-    check('declarationMap', 'declaration_map');
-    check('emitDeclarationOnly', 'emit_declaration_only');
-    check('resolveJsonModule', 'resolve_json_module');
-    check('sourceMap', 'source_map');
-    check('composite');
-    check('declaration');
-    check('incremental');
-    check('tsBuildInfoFile', 'ts_build_info_file');
-    check_preserve_jsx();
-    if (failures.length > 0) {
-        console.error("ERROR: ts_project rule " + target + " was configured with attributes that don't match the tsconfig");
-        failures.forEach(function (f) { return console.error(' - ' + f); });
-        console.error('You can automatically fix this by running:');
-        console.error("    npx @bazel/buildozer " + buildozerCmds.map(function (c) { return "'" + c + "'"; }).join(' ') + " " + target);
-        return 1;
-    }
-    // We have to write an output so that Bazel needs to execute this action.
-    // Make the output change whenever the attributes changed.
-    require('fs').writeFileSync(output, "\n// checked attributes for " + target + "\n// allow_js:              " + attrs.allow_js + "\n// composite:             " + attrs.composite + "\n// declaration:           " + attrs.declaration + "\n// declaration_map:       " + attrs.declaration_map + "\n// incremental:           " + attrs.incremental + "\n// source_map:            " + attrs.source_map + "\n// emit_declaration_only: " + attrs.emit_declaration_only + "\n// ts_build_info_file:    " + attrs.ts_build_info_file + "\n// preserve_jsx:          " + attrs.preserve_jsx + "\n", 'utf-8');
-    return 0;
-}
-if (require.main === module) {
-    try {
-        process.exitCode = main(process.argv.slice(2));
-        if (process.exitCode != 0) {
-            console.error('Or to suppress this error, run:');
-            console.error("    npx @bazel/buildozer 'set validate False' " + process.argv[4]);
-        }
-    }
-    catch (e) {
-        console.error(process.argv[1], e);
-    }
-}
diff --git a/nodejs/private/ts_validate_options.bzl b/nodejs/private/ts_validate_options.bzl
deleted file mode 100644
index 119662d..0000000
--- a/nodejs/private/ts_validate_options.bzl
+++ /dev/null
@@ -1,79 +0,0 @@
-"Helper rule to check that ts_project attributes match tsconfig.json properties"
-
-load(":ts_config.bzl", "TsConfigInfo")
-load(":ts_lib.bzl", "COMPILER_OPTION_ATTRS", "ValidOptionsInfo")
-
-def _tsconfig_inputs(ctx):
-    """Returns all transitively referenced tsconfig files from "tsconfig" and "extends" attributes."""
-    inputs = []
-    if TsConfigInfo in ctx.attr.tsconfig:
-        inputs.append(ctx.attr.tsconfig[TsConfigInfo].deps)
-    else:
-        inputs.append(depset([ctx.file.tsconfig]))
-    if hasattr(ctx.attr, "extends") and ctx.attr.extends:
-        if TsConfigInfo in ctx.attr.extends:
-            inputs.append(ctx.attr.extends[TsConfigInfo].deps)
-        else:
-            inputs.append(ctx.attr.extends.files)
-    return depset(transitive = inputs)
-
-def _validate_options_impl(ctx, run_action = None):
-    # Bazel won't run our action unless its output is needed, so make a marker file
-    # We make it a .d.ts file so we can plumb it to the deps of the ts_project compile.
-    marker = ctx.actions.declare_file("%s.optionsvalid.d.ts" % ctx.label.name)
-
-    arguments = ctx.actions.args()
-    config = struct(
-        allow_js = ctx.attr.allow_js,
-        declaration = ctx.attr.declaration,
-        declaration_map = ctx.attr.declaration_map,
-        has_local_deps = ctx.attr.has_local_deps,
-        preserve_jsx = ctx.attr.preserve_jsx,
-        composite = ctx.attr.composite,
-        emit_declaration_only = ctx.attr.emit_declaration_only,
-        resolve_json_module = ctx.attr.resolve_json_module,
-        source_map = ctx.attr.source_map,
-        incremental = ctx.attr.incremental,
-        ts_build_info_file = ctx.attr.ts_build_info_file,
-    )
-    arguments.add_all([ctx.file.tsconfig.path, marker.path, ctx.attr.target, json.encode(config)])
-
-    inputs = _tsconfig_inputs(ctx)
-
-    run_action_kwargs = {
-        "inputs": inputs,
-        "outputs": [marker],
-        "arguments": [arguments],
-        "env": {
-            "BINDIR": ctx.var["BINDIR"],
-        },
-    }
-    if run_action != None:
-        run_action(
-            ctx,
-            executable = "validator",
-            **run_action_kwargs
-        )
-    else:
-        ctx.actions.run(
-            executable = ctx.executable.validator,
-            **run_action_kwargs
-        )
-
-    return [
-        ValidOptionsInfo(marker = marker),
-    ]
-
-_ATTRS = dict(COMPILER_OPTION_ATTRS, **{
-    "has_local_deps": attr.bool(doc = "Whether any of the deps are in the local workspace"),
-    "target": attr.string(),
-    "ts_build_info_file": attr.string(),
-    "tsconfig": attr.label(mandatory = True, allow_single_file = [".json"]),
-    "validator": attr.label(mandatory = True, executable = True, cfg = "exec"),
-})
-
-lib = struct(
-    attrs = _ATTRS,
-    implementation = _validate_options_impl,
-    tsconfig_inputs = _tsconfig_inputs,
-)
diff --git a/packages/runfiles/BUILD.bazel b/packages/runfiles/BUILD.bazel
index 2997128..477c181 100644
--- a/packages/runfiles/BUILD.bazel
+++ b/packages/runfiles/BUILD.bazel
@@ -1,8 +1,8 @@
 load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
 load("@build_bazel_rules_nodejs//:tools/defaults.bzl", "pkg_npm")
-load("//packages/typescript:index.bzl", "ts_project")
+load("//internal:tsc.bzl", "tsc")
 
-ts_project(
+tsc(
     name = "runfiles_lib",
     srcs = glob(["*.ts"]),
     tsconfig = "tsconfig.json",
diff --git a/packages/typescript/BUILD.bazel b/packages/typescript/BUILD.bazel
deleted file mode 100644
index e69de29..0000000
--- a/packages/typescript/BUILD.bazel
+++ /dev/null
diff --git a/tools/defaults.bzl b/tools/defaults.bzl
index c6bff66..19a7ae1 100644
--- a/tools/defaults.bzl
+++ b/tools/defaults.bzl
@@ -76,6 +76,7 @@
     "@alexeagle",
     "@gregmagolan",
     "@mattem",
+    "@jbedard",
 ]
 
 def codeowners(name = "OWNERS", no_parent = False, **kwargs):