Unpublish ts_auto_deps.

PiperOrigin-RevId: 282807385
diff --git a/BUILD.bazel b/BUILD.bazel
index 7f69e55..b0a0051 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -45,8 +45,5 @@
         "//devserver:devserver-windows",
         "//internal:generated_BUILD",
         "//internal:tsc_wrapped",
-        "//ts_auto_deps:ts_auto_deps-darwin",
-        "//ts_auto_deps:ts_auto_deps-linux",
-        "//ts_auto_deps:ts_auto_deps-windows",
     ],
 )
diff --git a/README.md b/README.md
index 41028ad..8b1aceb 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@
 It contains these utilities:
 
 - `ts_devserver`: a Go library and binary that runs a fast local web server which concatenates JavaScript on-the-fly. It requires inputs in a named module format (module ids must be contained in the file, not inferred from the file's path).
-- `ts_auto_deps`: a Go library and binary which generates `BUILD.bazel` files from TypeScript sources.
 - `tsc_wrapped`: a TypeScript program which wraps the TypeScript compiler, hosting it under a Bazel worker.
 - `tsetse`: a collection of third-party "strictness" checks which we add to the TypeScript compiler.
 - `internal/common/*.bzl`: some Starlark utility code for running the `ts_library` rule.
diff --git a/package.bzl b/package.bzl
index 2e4473d..e1c4bb3 100644
--- a/package.bzl
+++ b/package.bzl
@@ -42,7 +42,7 @@
         sha256 = "f624fe9ca8d51de192655369ac538c420afb7cde16e1ad052554b582fff09287",
     )
 
-    # For building ts_devserver and ts_auto_deps binaries
+    # For building ts_devserver binary
     # See https://github.com/bazelbuild/rules_go#setup for the latest version.
     _maybe(
         http_archive,
@@ -77,15 +77,6 @@
         sha256 = "3c681998538231a2d24d0c07ed5a7658cb72bfb5fd4bf9911157c0e9ac6a2687",
     )
 
-    # ts_auto_deps depends on com_github_bazelbuild_buildtools
-    _maybe(
-        http_archive,
-        name = "com_github_bazelbuild_buildtools",
-        url = "https://github.com/bazelbuild/buildtools/archive/0.19.2.1.zip",
-        strip_prefix = "buildtools-0.19.2.1",
-        sha256 = "9176a7df34dbed2cf5171eb56271868824560364e60644348219f852f593ae79",
-    )
-
 def _maybe(repo_rule, name, **kwargs):
     if not native.existing_rule(name):
         repo_rule(name = name, **kwargs)
diff --git a/ts_auto_deps/BUILD.bazel b/ts_auto_deps/BUILD.bazel
deleted file mode 100644
index b71e8a1..0000000
--- a/ts_auto_deps/BUILD.bazel
+++ /dev/null
@@ -1,48 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-
-go_library(
-    name = "go_default_library",
-    srcs = ["main.go"],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps",
-    visibility = ["//visibility:private"],
-    deps = [
-        "//ts_auto_deps/platform:go_default_library",
-        "//ts_auto_deps/updater:go_default_library",
-    ],
-)
-
-go_binary(
-    name = "ts_auto_deps_bin",
-    embed = [":go_default_library"],
-    visibility = ["//visibility:public"],
-)
-
-go_binary(
-    name = "ts_auto_deps-darwin",
-    out = "ts_auto_deps-darwin_x64",
-    embed = [":go_default_library"],
-    goarch = "amd64",
-    goos = "darwin",
-    pure = "on",
-    visibility = ["//visibility:public"],
-)
-
-go_binary(
-    name = "ts_auto_deps-linux",
-    out = "ts_auto_deps-linux_x64",
-    embed = [":go_default_library"],
-    goarch = "amd64",
-    goos = "linux",
-    pure = "on",
-    visibility = ["//visibility:public"],
-)
-
-go_binary(
-    name = "ts_auto_deps-windows",
-    out = "ts_auto_deps-win32_x64.exe",
-    embed = [":go_default_library"],
-    goarch = "amd64",
-    goos = "windows",
-    pure = "on",
-    visibility = ["//visibility:public"],
-)
diff --git a/ts_auto_deps/analyze/BUILD.bazel b/ts_auto_deps/analyze/BUILD.bazel
deleted file mode 100644
index 29213ce..0000000
--- a/ts_auto_deps/analyze/BUILD.bazel
+++ /dev/null
@@ -1,37 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-
-go_library(
-    name = "go_default_library",
-    srcs = [
-        "analyze.go",
-        "imports.go",
-        "loader.go",
-    ],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/analyze",
-    visibility = ["//visibility:public"],
-    deps = [
-        "//ts_auto_deps/platform:go_default_library",
-        "//ts_auto_deps/proto:go_default_library",
-        "//ts_auto_deps/workspace:go_default_library",
-        "@com_github_bazelbuild_buildtools//build_proto:go_default_library",
-        "@com_github_bazelbuild_buildtools//edit:go_default_library",
-        "@com_github_golang_protobuf//proto:go_default_library",
-    ],
-)
-
-go_test(
-    name = "go_default_test",
-    srcs = [
-        "analyze_test.go",
-        "imports_test.go",
-        "loader_test.go",
-    ],
-    embed = [":go_default_library"],
-    deps = [
-        "//ts_auto_deps/platform:go_default_library",
-        "//ts_auto_deps/proto:go_default_library",
-        "@com_github_bazelbuild_buildtools//build_proto:go_default_library",
-        "@com_github_golang_protobuf//proto:go_default_library",
-        "@com_github_kylelemons_godebug//pretty:go_default_library",
-    ],
-)
diff --git a/ts_auto_deps/analyze/analyze.go b/ts_auto_deps/analyze/analyze.go
deleted file mode 100644
index 9e005cc..0000000
--- a/ts_auto_deps/analyze/analyze.go
+++ /dev/null
@@ -1,603 +0,0 @@
-// Package analyze uses bazel query to determine and locate missing imports
-// in TypeScript source files.
-package analyze
-
-import (
-	"context"
-	"fmt"
-	"os"
-	"path/filepath"
-	"regexp"
-	"strings"
-
-	"github.com/bazelbuild/buildtools/edit"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/workspace"
-	"github.com/golang/protobuf/proto"
-
-	appb "github.com/bazelbuild/buildtools/build_proto"
-	arpb "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto"
-)
-
-var (
-	extensions = []string{
-		// '.d.ts' must come before '.ts' to completely remove the '.d.ts'
-		// extension.
-		".d.ts",
-		".ts",
-		".tsx",
-	}
-)
-
-const (
-	// debug enables/disables debug logging. Set to true to have debug statements
-	// print to stdout, set to false to disable debug statements.
-	debug = false
-)
-
-// debugf prints a formatted message prefixed with "DEBUG:" if the debug
-// flag is enabled.
-func debugf(format string, v ...interface{}) {
-	if debug {
-		fmt.Printf(fmt.Sprintf("DEBUG: %s\n", format), v...)
-	}
-}
-
-// TargetLoader provides methods for loading targets from BUILD files.
-type TargetLoader interface {
-	// LoadTargets loads targets from BUILD files associated with labels. A target
-	// is a rule, source file, generated file, package group or environment group.
-	// It returns a mapping from labels to targets or an error, if any occurred.
-	//
-	// A label must be the absolute label associated with a target. For example,
-	// '//foo/bar:baz' is acceptable whereas 'bar:baz' or '//foo/bar' will result
-	// in undefined behavior. TODO(lucassloan): make this an error
-	//
-	// Only returns targets visible to currentPkg. If currentPkg is an empty
-	// string returns all targets regardless of visibility.
-	LoadTargets(currentPkg string, labels []string) (map[string]*appb.Target, error)
-	// LoadRules loads rules from BUILD files associated with labels.
-	// It returns a mapping from labels to rules or an error, if any
-	// occurred.
-	//
-	// A label must be the absolute label associated with a rule. For
-	// example, '//foo/bar:baz' is acceptable whereas 'bar:baz' or '//foo/bar'
-	// will result in undefined behavior.
-	// TODO(lucassloan): make this an error.
-	//
-	// Only returns rules visible to currentPkg. If currentPkg is an empty string
-	// returns all rules regardless of visibility.
-	LoadRules(currentPkg string, labels []string) (map[string]*appb.Rule, error)
-	// LoadImportPaths loads targets from BUILD files associated with import
-	// paths relative to a root directory. It returns a mapping from import
-	// paths to targets or an error, if any occurred.
-	//
-	// An import path is the path present in a TypeScript import statement
-	// resolved relative to the workspace root. For example, an import
-	// statement 'import baz from "../baz.ts"' declared in the TypeScript
-	// source file '//foo/bar.ts' would have the import path of 'baz.ts'. If
-	// no target is found associated with a provided import path, the import
-	// path should be excluded from the returned mapping but an error should
-	// not be returned.
-	//
-	// Only returns rules visible to currentPkg. If currentPkg is an empty string
-	// returns all targets regardless of visibility.
-	LoadImportPaths(ctx context.Context, targetToAnalyze *appb.Rule, currentPkg, root string, paths []string) (map[string]*appb.Rule, error)
-}
-
-// Analyzer uses a BuildLoader to generate dependency reports.
-type Analyzer struct {
-	loader TargetLoader
-}
-
-// New returns a new Analyzer which can be used to generate dependency reports.
-func New(loader TargetLoader) *Analyzer {
-	return &Analyzer{loader: loader}
-}
-
-// Analyze generates a dependency report for each target label in labels.
-//
-// dir is the directory that ts_auto_deps should execute in. Must be a sub-directory
-// of the workspace root.
-func (a *Analyzer) Analyze(ctx context.Context, dir string, labels []string) ([]*arpb.DependencyReport, error) {
-	if len(labels) == 0 {
-		return nil, nil
-	}
-	_, currentPkg, _ := edit.ParseLabel(labels[0])
-	for _, label := range labels {
-		if _, pkg, _ := edit.ParseLabel(label); pkg != currentPkg {
-			return nil, fmt.Errorf("can't analyze targets in different packages")
-		}
-	}
-	root, err := workspace.Root(dir)
-	if err != nil {
-		return nil, err
-	}
-	rules, err := a.loader.LoadRules(currentPkg, labels)
-	if err != nil {
-		return nil, err
-	}
-	resolved, err := a.resolveImportsForTargets(ctx, currentPkg, root, rules)
-	if err != nil {
-		return nil, err
-	}
-	return a.generateReports(labels, resolved)
-}
-
-// resolvedTarget represents a Bazel target and all resolved information.
-type resolvedTarget struct {
-	label string
-	// A map of all existing dependencies on a target at the time of analysis.
-	// The keys are labels and the values are thes loaded target.
-	dependencies map[string]*appb.Rule
-	// A map of source file paths to their imports.
-	imports map[string][]*ts_auto_depsImport
-	// rule is the original rule the target was constructed from.
-	rule *appb.Rule
-	// missingSources are source files which could not be opened on disk.
-	// These are added to the dependency reports and MissingSources.
-	missingSources []string
-	// A map from the labels in the target's srcs to the Targets those
-	// labels refer.
-	sources              map[string]*appb.Target
-	literalSourcePaths   []string
-	generatedSourcePaths []string
-}
-
-// setSources sets the sources on t.  It returns an error if one of the srcs of
-// t's rule isn't in loadedSrcs.  It also sorts the sources into literal and
-// generated sources, setting literalSourcePaths and generatedSourcePaths.
-// Returns an error if all the sources are generated - ts_auto_deps can't read the
-// import statements to determine deps.
-func (t *resolvedTarget) setSources(loadedSrcs map[string]*appb.Target) error {
-	for _, label := range listAttribute(t.rule, "srcs") {
-		src := loadedSrcs[label]
-		if src == nil {
-			return fmt.Errorf("no source found for label %s", label)
-		}
-		t.sources[label] = src
-		if src.GetType() == appb.Target_SOURCE_FILE {
-			t.literalSourcePaths = append(t.literalSourcePaths, labelToPath(label))
-		} else {
-			t.generatedSourcePaths = append(t.generatedSourcePaths, labelToPath(label))
-		}
-	}
-	if len(t.literalSourcePaths) == 0 && len(t.generatedSourcePaths) > 0 {
-		return fmt.Errorf("rule has generated sources - cannot determine dependencies")
-	}
-	return nil
-}
-
-// srcs returns the labels of the sources of t.
-func (t *resolvedTarget) srcs() ([]string, error) {
-	srcs := listAttribute(t.rule, "srcs")
-	if srcs == nil {
-		return nil, fmt.Errorf("target %q missing \"srcs\" attribute", t.label)
-	}
-
-	return srcs, nil
-}
-
-// getAllLiteralSrcPaths returns the file paths of all the non-generated sources
-// of the targets.
-func getAllLiteralSrcPaths(targets map[string]*resolvedTarget) ([]string, error) {
-	var allLiteralSrcPaths []string
-	for _, t := range targets {
-		allLiteralSrcPaths = append(allLiteralSrcPaths, t.literalSourcePaths...)
-	}
-
-	return allLiteralSrcPaths, nil
-}
-
-func (t *resolvedTarget) deps() []string {
-	return listAttribute(t.rule, "deps")
-}
-
-// provides returns whether the resolved target can provide the path provided.
-func (t *resolvedTarget) provides(path string) bool {
-	for _, label := range listAttribute(t.rule, "srcs") {
-		src := t.sources[label]
-		if src.GetType() == appb.Target_SOURCE_FILE {
-			// For literal sources, check the path of the source
-			if labelToPath(label) == path {
-				return true
-			}
-		} else if src.GetType() == appb.Target_RULE {
-			// For generated souces, check against the paths of rule's
-			// outputs
-			for _, genSrc := range src.GetRule().GetRuleOutput() {
-				if labelToPath(genSrc) == path {
-					return true
-				}
-			}
-		}
-	}
-	return false
-}
-
-// newTarget constructs a new target instance from a loaded rule.
-func newResolvedTarget(r *appb.Rule) *resolvedTarget {
-	return &resolvedTarget{
-		label:        r.GetName(),
-		dependencies: make(map[string]*appb.Rule),
-		imports:      make(map[string][]*ts_auto_depsImport),
-		rule:         r,
-		sources:      make(map[string]*appb.Target),
-	}
-}
-
-// resolveImportsForTargets attempts to resolve the imports in the sources of
-// each target in targets.
-func (a *Analyzer) resolveImportsForTargets(ctx context.Context, currentPkg, root string, allTargets map[string]*appb.Rule) (map[string]*resolvedTarget, error) {
-	targets := make(map[string]*resolvedTarget)
-	var allDeps, allSrcs []string
-	for _, t := range allTargets {
-		target := newResolvedTarget(t)
-		targets[target.label] = target
-		srcs, err := target.srcs()
-		if err != nil {
-			return nil, err
-		}
-		allDeps = append(allDeps, target.deps()...)
-		allSrcs = append(allSrcs, srcs...)
-	}
-	deps, err := a.loader.LoadRules(currentPkg, allDeps)
-	if err != nil {
-		return nil, err
-	}
-	// Associate the loaded existing deps with the target or targets which
-	// contained them.
-	for _, t := range targets {
-		for _, dep := range t.deps() {
-			t.dependencies[dep] = deps[dep]
-		}
-	}
-	// load all the sources in the targets, so that literal and generated
-	// targets can be distinguished
-	srcs, err := a.loader.LoadTargets(currentPkg, allSrcs)
-	if err != nil {
-		return nil, err
-	}
-	for _, t := range targets {
-		err := t.setSources(srcs)
-		if err != nil {
-			return nil, err
-		}
-	}
-	// only extract the imports out of the literal sources, since ts_auto_deps can't
-	// see the contents of generated files
-	allLiteralSrcPaths, err := getAllLiteralSrcPaths(targets)
-	if err != nil {
-		return nil, err
-	}
-	imports, errs := extractAllImports(root, allLiteralSrcPaths)
-	for _, err := range errs {
-		// NotExist errors are caught and added to the generated dependency
-		// reports as missing source files. Only errors which are not NotExist
-		// errors should be reported.
-		if !os.IsNotExist(err) {
-			return nil, err
-		}
-	}
-	for _, t := range targets {
-		srcs := t.literalSourcePaths
-		for _, src := range srcs {
-			v, ok := imports[src]
-			if ok {
-				t.imports[src] = v
-			} else {
-				// The source was not found on disk during import extraction.
-				t.missingSources = append(t.missingSources, relativePathLabel(t.label, src))
-			}
-		}
-	}
-	if err := a.resolveImports(ctx, currentPkg, root, targets); err != nil {
-		return nil, err
-	}
-	return targets, nil
-}
-
-// resolveImports finds targets which provide the imported file or library
-// for imports without known targets.
-func (a *Analyzer) resolveImports(ctx context.Context, currentPkg, root string, targets map[string]*resolvedTarget) error {
-	for _, target := range targets {
-		var paths []string
-		needingResolution := make(map[string][]*ts_auto_depsImport)
-		for _, imports := range target.imports {
-		handlingImports:
-			for _, imp := range imports {
-				resolvedPath := imp.resolvedPath()
-				for _, path := range pathWithExtensions(resolvedPath) {
-					if target.provides(path) {
-						imp.knownTarget = target.label
-						continue handlingImports
-					}
-				}
-				d, err := a.findExistingDepProvidingImport(ctx, root, target, imp)
-				if err != nil {
-					return err
-				}
-				if d == "" {
-					// A target providing the import was not found on the
-					// existing dependencies or in a comment. Use other
-					// heuristics.
-					paths = append(paths, resolvedPath)
-					needingResolution[resolvedPath] = append(needingResolution[resolvedPath], imp)
-					continue
-				}
-				imp.knownTarget = d
-			}
-		}
-		if len(needingResolution) == 0 {
-			continue
-		}
-		res, err := a.loader.LoadImportPaths(ctx, target.rule, currentPkg, root, paths)
-		if err != nil {
-			return err
-		}
-		for path, imports := range needingResolution {
-			if target, ok := res[path]; ok {
-				for _, imp := range imports {
-					imp.knownTarget = redirectedLabel(target)
-				}
-			}
-		}
-	}
-	return nil
-}
-
-func pathWithExtensions(basename string) []string {
-	var paths []string
-	for _, ext := range extensions {
-		paths = append(paths, basename+ext)
-	}
-	return paths
-}
-
-var ambientModuleDeclRE = regexp.MustCompile("(?m)^\\s*declare\\s+module\\s+['\"]([^'\"]+)['\"]\\s+\\{")
-
-// findExistingDepProvidingImport looks through a map of the existing deps to
-// see if any of them provide the import in a way that can't be queried
-// for.  E.g. if the build rule has a "module_name" attribute or if one
-// of the .d.ts sources has an ambient module declaration.
-//
-// If the import already has a knownTarget, findRuleProvidingImport will
-// return the knownTarget.
-func (a *Analyzer) findExistingDepProvidingImport(ctx context.Context, root string, rt *resolvedTarget, i *ts_auto_depsImport) (string, error) {
-	if i.knownTarget != "" {
-		return i.knownTarget, nil
-	}
-
-	// check if any of the existing deps declare a module_name that matches the import
-	for _, r := range rt.dependencies {
-		resolvedImportPath := resolveAgainstModuleRoot(r, i.importPath)
-		if resolvedImportPath == i.importPath {
-			continue
-		}
-
-		// enumerate all the possible filepaths for the resolved import path, and
-		// compare against all the srcs
-		possibleImportPaths := possibleFilepaths(resolvedImportPath)
-		for _, src := range listAttribute(r, "srcs") {
-			for _, mi := range possibleImportPaths {
-				if mi == labelToPath(src) {
-					return r.GetName(), nil
-				}
-			}
-		}
-	}
-
-	// check if any of the other sources or the souces of any of the deps are .d.ts
-	// files which have ambient module declarations
-	var allRules []*appb.Rule
-	for _, r := range rt.dependencies {
-		allRules = append(allRules, r)
-	}
-	allRules = append(allRules, rt.rule)
-	for _, r := range allRules {
-		for _, src := range listAttribute(r, "srcs") {
-			fp := filepath.Join(root, labelToPath(src))
-			if !strings.HasSuffix(fp, ".d.ts") {
-				continue
-			}
-
-			contents, err := platform.ReadFile(ctx, fp)
-			if err != nil {
-				return "", fmt.Errorf("error reading file looking for ambient module decls: %s", err)
-			}
-
-			matches := ambientModuleDeclRE.FindAllStringSubmatch(string(contents), -1)
-
-			// put all the ambient modules into a set
-			declaredModules := make(map[string]bool)
-			for _, match := range matches {
-				declaredModules[match[1]] = true
-			}
-
-			// remove all the modules that were imported (ie all the modules that
-			// were being augmented/re-opened)
-			for _, mi := range parseImports(fp, contents) {
-				delete(declaredModules, mi.importPath)
-			}
-
-			if declaredModules[i.importPath] {
-				debugf("found import %s in ambient module declaration in %s", i.importPath, r.GetName())
-				return r.GetName(), nil
-			}
-		}
-	}
-	return "", nil
-}
-
-// stripTSExtension removes TypeScript extensions from a file path. If no
-// TypeScript extensions are present, the filepath is returned unaltered.
-func stripTSExtension(path string) string {
-	for _, ext := range extensions {
-		if strings.HasSuffix(path, ext) {
-			return strings.TrimSuffix(path, ext)
-		}
-	}
-	return path
-}
-
-// redirectedLabel looks in the target's tags for a tag starting with
-// 'alt_dep=' followed by a label. If such a tag is found, the label is
-// returned. Otherwise, the target's own label is returned.
-func redirectedLabel(target *appb.Rule) string {
-	for _, tag := range listAttribute(target, "tags") {
-		if trimmedTag := strings.TrimPrefix(tag, "alt_dep="); trimmedTag != tag {
-			return trimmedTag
-		}
-	}
-	// No 'alt_dep=' tag was present on the target so no redirects need to occur.
-	return target.GetName()
-}
-
-func labelToPath(label string) string {
-	_, pkg, file := edit.ParseLabel(label)
-	return platform.Normalize(filepath.Clean(filepath.Join(pkg, file)))
-}
-
-// generateReports generates reports for each label in labels.
-func (a *Analyzer) generateReports(labels []string, labelToTarget map[string]*resolvedTarget) ([]*arpb.DependencyReport, error) {
-	reports := make([]*arpb.DependencyReport, 0, len(labels))
-	for _, label := range labels {
-		target, ok := labelToTarget[label]
-		if !ok {
-			// This case should never happen.
-			platform.Fatalf("target %s no longer loaded", label)
-		}
-		report, err := a.generateReport(target)
-		if err != nil {
-			return nil, err
-		}
-		reports = append(reports, report)
-	}
-	return reports, nil
-}
-
-// generateReport generates a dependency report for a target.
-//
-// It adds imports for which no target could be found to unresolved imports.
-// Imports which had locatable targets are added to the necessary dependency
-// or missing dependency properties if the import was already present on target
-// or the import was not already present respectively.
-//
-// Missing source files detected during import resolution are added to the
-// reports. Dependencies which were present on the initial target but are not
-// required are added to the unnecessary dependency array.
-func (a *Analyzer) generateReport(target *resolvedTarget) (*arpb.DependencyReport, error) {
-	usedDeps := make(map[string]bool)
-	report := &arpb.DependencyReport{
-		Rule:              proto.String(target.label),
-		MissingSourceFile: target.missingSources,
-	}
-	for _, imports := range target.imports {
-	handlingImports:
-		for _, imp := range imports {
-			if imp.knownTarget == target.label {
-				continue
-			}
-			if imp.knownTarget == "" {
-				if strings.HasPrefix(imp.importPath, "goog:") {
-					// This feedback needs to be phrased this way since the
-					// updater.go relies on parsing the feedback strings to
-					// determine which 'goog:' imports to add.
-					report.Feedback = append(report.Feedback,
-						fmt.Sprintf(
-							"ERROR: %s:%d:%d: missing comment for 'goog:' import, "+
-								"please add a trailing comment to the import. E.g.\n  "+
-								"import Bar from '%s'; // from //foo:bar",
-							imp.location.sourcePath, imp.location.line, imp.location.offset, imp.importPath))
-				}
-				report.UnresolvedImport = append(report.UnresolvedImport, imp.resolvedPath())
-				continue
-			}
-
-			for _, dep := range target.deps() {
-				if edit.LabelsEqual(dep, imp.knownTarget, "") {
-					// fmt.Printf("%s provides %s\n", dep, imp.importPath)
-					usedDeps[dep] = true
-					report.NecessaryDependency = append(report.NecessaryDependency, imp.knownTarget)
-					continue handlingImports
-				}
-			}
-			report.MissingDependencyGroup = append(report.MissingDependencyGroup, &arpb.DependencyGroup{
-				Dependency: []string{edit.ShortenLabel(imp.knownTarget, "")},
-				ImportPath: []string{imp.importPath},
-			})
-		}
-	}
-
-	var unusedDeps []string
-	for _, dep := range target.deps() {
-		if _, ok := usedDeps[dep]; !ok {
-			unusedDeps = append(unusedDeps, dep)
-		}
-	}
-	labelToRule, err := a.loader.LoadRules("", unusedDeps)
-	if err != nil {
-		return nil, err
-	}
-	for label, rule := range labelToRule {
-		switch class := rule.GetRuleClass(); class {
-		case "ts_declaration":
-			// TypeScript declarations might declare arbitrary global symbols, so it
-			// is impossible to detect reliably if the import is being used (without
-			// compiling, at least).  Report that the rule has no explicit import as a
-			// warning, so that ts_auto_deps can decide to import remove or not based on a
-			// flag.
-			warning := fmt.Sprintf("WARNING: %s: keeping possibly used %s '%s'", rule.GetLocation(), class, label)
-			report.Feedback = append(report.Feedback, warning)
-		case "css_library":
-			// Similar to ts_declaration, ts_auto_deps can't reliably detect if css_library
-			// imports are being used, since ts_auto_deps can't currently parse @requirecss
-			// annotations.  Unlike ts_declaration, there's no flag to remove them, so
-			// there's no need to report a warning.
-		default:
-			// The contents of generated files aren't visible, so ts_auto_deps can't discover
-			// the import statements/deps that they contain.  To be safe, don't remove
-			// any unused deps, since they might be used by the generated file(s).
-			if len(target.generatedSourcePaths) == 0 {
-				report.UnnecessaryDependency = append(report.UnnecessaryDependency, label)
-			}
-		}
-	}
-	return report, nil
-}
-
-// relativePathLabel converts src to a label for a path relative to the
-// provided target. For example, a target '//foo/bar' and a src 'foo/bar/baz.ts'
-// would result in a relative path label of '//foo/bar:baz.ts'.
-func relativePathLabel(label, src string) string {
-	_, pkg, _ := edit.ParseLabel(label)
-	return fmt.Sprintf("//%s:%s", pkg, strings.TrimPrefix(src, pkg+"/"))
-}
-
-// listAttribute retrieves the attribute from target with name.
-func listAttribute(target *appb.Rule, name string) []string {
-	if a := attribute(target, name); a != nil {
-		return a.GetStringListValue()
-	}
-	return nil
-}
-
-func stringAttribute(target *appb.Rule, name string) string {
-	if a := attribute(target, name); a != nil {
-		return a.GetStringValue()
-	}
-	return ""
-}
-
-func attribute(target *appb.Rule, name string) *appb.Attribute {
-	for _, a := range target.GetAttribute() {
-		if a.GetName() == name {
-			return a
-		}
-	}
-	return nil
-}
-
-func isGenerated(rule *appb.Rule) bool {
-	return stringAttribute(rule, "generator_name") != ""
-}
diff --git a/ts_auto_deps/analyze/analyze_test.go b/ts_auto_deps/analyze/analyze_test.go
deleted file mode 100644
index 7a7d90a..0000000
--- a/ts_auto_deps/analyze/analyze_test.go
+++ /dev/null
@@ -1,657 +0,0 @@
-package analyze
-
-import (
-	"context"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/golang/protobuf/proto"
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/cmpopts"
-	"github.com/kylelemons/godebug/pretty"
-
-	appb "github.com/bazelbuild/buildtools/build_proto"
-	arpb "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto"
-)
-
-var (
-	testTmpDir = os.Getenv("TEST_TMPDIR")
-)
-
-func TestMain(m *testing.M) {
-	if err := createWorkspaceFile(); err != nil {
-		platform.Fatalf("failed to create WORKSPACE file: %q", err)
-	}
-	os.Exit(m.Run())
-}
-
-const (
-	testDirectory = "a"
-)
-
-type fakeTargetLoader struct {
-	targetsByLabels      map[string]string
-	targetsByImportPaths map[string]string
-}
-
-func newFakeTargetLoader() *fakeTargetLoader {
-	return &fakeTargetLoader{
-		targetsByLabels:      make(map[string]string),
-		targetsByImportPaths: make(map[string]string),
-	}
-}
-
-func (bl *fakeTargetLoader) LoadRules(_ string, labels []string) (map[string]*appb.Rule, error) {
-	return bl.loadRules(bl.targetsByLabels, labels)
-}
-
-func (bl *fakeTargetLoader) LoadTargets(_ string, labels []string) (map[string]*appb.Target, error) {
-	targets := make(map[string]*appb.Target)
-	for _, l := range labels {
-		if strings.Contains(l, ".") {
-			targets[l] = &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()}
-		} else {
-			targets[l] = &appb.Target{Type: appb.Target_RULE.Enum()}
-		}
-	}
-	return targets, nil
-}
-
-func (bl *fakeTargetLoader) byLabel(label, value string) {
-	bl.targetsByLabels[label] = value
-}
-
-func (bl *fakeTargetLoader) LoadImportPaths(_ context.Context, _ *appb.Rule, _, _ string, paths []string) (map[string]*appb.Rule, error) {
-	return bl.loadRules(bl.targetsByImportPaths, paths)
-}
-
-func (bl *fakeTargetLoader) byImportPath(importPath, value string) {
-	bl.targetsByImportPaths[importPath] = value
-}
-
-func (bl *fakeTargetLoader) loadRules(source map[string]string, keys []string) (map[string]*appb.Rule, error) {
-	targets := make(map[string]*appb.Rule)
-	for _, key := range keys {
-		value, ok := source[key]
-		if !ok {
-			return nil, nil
-		}
-		var target appb.Rule
-		if err := proto.UnmarshalText(strings.Trim(value, " \n\r\t"), &target); err != nil {
-			return nil, err
-		}
-		targets[key] = &target
-	}
-	return targets, nil
-}
-
-type file struct {
-	path     string
-	contents []string
-}
-
-// testTarget represents a target with a label, a proto literal, and any import
-// paths that should resolve to the target.
-type testTarget struct {
-	label, protoLiteral string
-	importPaths         []string
-}
-
-func analyzeTargets(t *testing.T, labels []string, targets []*testTarget, files []*file) []*arpb.DependencyReport {
-	t.Helper()
-	for _, file := range files {
-		path := filepath.Join(testDirectory, file.path)
-		if err := createFile(path, file.contents...); err != nil {
-			t.Errorf("failed to create file %q: %q", file.path, err)
-			return nil
-		}
-		defer os.Remove(path)
-	}
-	for i, label := range labels {
-		labels[i] = fmt.Sprintf("//%s:%s", testDirectory, label)
-	}
-	loader := newFakeTargetLoader()
-	for _, t := range targets {
-		label := t.label
-		if !strings.HasPrefix(label, "//") {
-			label = fmt.Sprintf("//%s:%s", testDirectory, label)
-		}
-		r := fmt.Sprintf("name: %q\n%s", label, t.protoLiteral)
-		loader.byLabel(label, r)
-		for _, i := range t.importPaths {
-			loader.byImportPath(i, r)
-		}
-	}
-	r, err := New(loader).Analyze(context.Background(), testTmpDir, labels)
-	if err != nil {
-		t.Errorf("Analyze(%q): failed to generate reports: %q", labels, err)
-		return nil
-	}
-	if len(r) != len(labels) {
-		t.Errorf("Analyze(%q): got %d reports, wanted %d", labels, len(r), len(labels))
-		return nil
-	}
-	return r
-}
-
-func TestUnresolvedImports(t *testing.T) {
-	tests := []struct {
-		filepath, fileContents string
-		expectedImports        []string
-	}{
-		{"b/importer.ts", "import X from './path';", []string{"a/b/path"}},
-		{"b/importer.ts", "import X from 'absolute/path';", []string{"absolute/path"}},
-		{"b/importer.ts", "import X from '../../root';", []string{"root"}},
-		{"b/importer.ts", "import X from './multi/subpath';", []string{"a/b/multi/subpath"}},
-		{"b/importer.ts", "import X from '/rooted';", []string{"/rooted"}},
-		{"b/importer.ts", "import X from 'absolute/path';\nimport Y from './path';", []string{"absolute/path", "a/b/path"}},
-		{"b/importer.ts", "import X from 'some/path'; // from  //target:location", nil},
-		{"importer.d.ts", "import y from 'some/thing/missing';", []string{"some/thing/missing"}},
-	}
-	for _, test := range tests {
-		r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-			{"a_lib", fmt.Sprintf(`
-				rule_class: "ts_library"
-				attribute: <
-					name: "srcs"
-					string_list_value: "//a:%s"
-					type: 5
-				>`, test.filepath), nil},
-		}, []*file{{test.filepath, []string{test.fileContents}}})
-		if r == nil {
-			continue
-		}
-		if diff := pretty.Compare(r[0].GetUnresolvedImport(), test.expectedImports); diff != "" {
-			t.Errorf("Analyze(%q): failed to detect unresolved imports: (-got, +want)\n%s", test.fileContents, diff)
-		}
-	}
-}
-
-func TestUnnecessaryDependencies(t *testing.T) {
-	tests := [][]string{
-		[]string{"/* nothing */"},
-	}
-	for _, test := range tests {
-		r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-			{"a_lib", `
-				rule_class: "ts_library"
-				attribute: <
-					name: "srcs"
-					string_list_value: "//a:importer.ts"
-					type: 5
-				>
-				attribute: <
-					name: "deps"
-					string_list_value: "//a:b_lib"
-					type: 5
-				>`, nil},
-			{"b_lib", `
-				rule_class: "ts_library"`, nil},
-		}, []*file{{"t/importer.ts", test}})
-		if r == nil {
-			continue
-		}
-		if diff := pretty.Compare(r[0].GetUnnecessaryDependency(), []string{"//a:b_lib"}); diff != "" {
-			t.Errorf("Analyze(%q): failed to detect unnecessary dependencies: (-got, +want)\n%s", test, diff)
-		}
-	}
-}
-
-func TestNecessaryDependencies(t *testing.T) {
-	tests := [][]string{
-		[]string{"import x from 'b/target';"},
-		[]string{"// ts_auto_deps: x from //b:b_lib"},
-		[]string{"export x from 'b/target';"},
-	}
-	for _, test := range tests {
-		r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-			{"a_lib", `
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "//a:importer.ts"
-				>
-				attribute: <
-					type: 5
-					name: "deps"
-					string_list_value: "//b:b_lib"
-				>`, nil},
-			{"//b:b_lib", `
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "//b:target.ts"
-				>`, []string{"b/target"}},
-		}, []*file{{"importer.ts", test}})
-		if r == nil {
-			continue
-		}
-		if diff := pretty.Compare(r[0].GetNecessaryDependency(), []string{"//b:b_lib"}); diff != "" {
-			t.Errorf("Analyze(%q): failed to detect necessary deps: (-got, +want)\n%s", test, diff)
-		}
-	}
-}
-
-func TestMissingDependencies(t *testing.T) {
-	tests := []struct {
-		fileContents string
-		missingDeps  []string
-	}{
-		{"import x from 'b/c';\nimport y from 'angular';", []string{"//b/c:b_lib", "//third_party/javascript/typings/angular"}},
-		{"import * as angular from 'angular';\ndeclare module 'angular' { /* reopen */ }", []string{"//third_party/javascript/typings/angular"}},
-	}
-	for _, test := range tests {
-		r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-			{"a_lib", `
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "//a:x.ts"
-				>`, nil},
-			{"//b/c:b_lib", `
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "//b/c:index.ts"
-				>`, []string{"b/c"}},
-			{"//third_party/javascript/typings/angular:angular", `
-				rule_class: "ts_declaration"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "//third_party/javascript/typings/angular:index.d.ts"
-				>`, []string{"angular"}},
-		}, []*file{{"x.ts", []string{test.fileContents}}})
-		if r == nil {
-			continue
-		}
-		if diff := pretty.Compare(missingDeps(r[0]), test.missingDeps); diff != "" {
-			t.Errorf("Analyze(%q): failed to detect missing dependencies: (-got, +want)\n%s", test.fileContents, diff)
-		}
-	}
-}
-
-func TestMissingSourceFile(t *testing.T) {
-	r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-		{"a_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//a:f1.ts"
-				string_list_value: "//a:f2.ts"
-				string_list_value: "//a:p/f3.ts"
-			>`, nil},
-	}, []*file{{"f1.ts", []string{"/* nothing */"}}})
-	if r == nil {
-		t.FailNow()
-	}
-	if diff := pretty.Compare(r[0].GetMissingSourceFile(), []string{"//a:f2.ts", "//a:p/f3.ts"}); diff != "" {
-		t.Fatalf("Analyze: failed to detect missing source files: (-got, +want)\n%s", diff)
-	}
-}
-
-func TestMultipleLabels(t *testing.T) {
-	r := analyzeTargets(t, []string{"a_lib", "b_lib"}, []*testTarget{
-		{"a_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//a:a/importer.ts"
-			>`, nil},
-		{"b_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//a:b/importer.ts"
-			>`, nil},
-	}, []*file{
-		{"a/importer.ts", []string{"import X from './path';"}},
-		{"b/importer.ts", []string{"import X from './path';"}},
-	})
-	if r == nil {
-		t.FailNow()
-	}
-	tests := []struct {
-		label             string
-		unresolvedImports []string
-	}{
-		{"a_lib", []string{"a/a/path"}},
-		{"b_lib", []string{"a/b/path"}},
-	}
-	for i, test := range tests {
-		report := r[i]
-		if diff := pretty.Compare(report.GetUnresolvedImport(), test.unresolvedImports); diff != "" {
-			t.Errorf("Analyze(%q): failed to detect unresolved imports: (-got, +want)\n%s", test.label, diff)
-		}
-	}
-}
-
-func TestMultipleSourceFiles(t *testing.T) {
-	r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-		{"a_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//a:importer.ts"
-				string_list_value: "//a:exporter.ts"
-			>`, nil},
-	}, []*file{
-		{"importer.ts", []string{"import {x} from 'a/exporter';"}},
-		{"exporter.ts", []string{"export let x = 12;"}},
-	})
-	if r == nil {
-		t.FailNow()
-	}
-	if diff := pretty.Compare(missingDeps(r[0]), []string{}); diff != "" {
-		t.Fatalf("Analyze: failed to detect missing dependencies: (-got, +want)\n%s", diff)
-	}
-}
-
-func TestRedirectTag(t *testing.T) {
-	r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-		{"a_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//a:x.ts"
-			>`, nil},
-		{"dlib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "deps"
-				string_list_value: "//b:clib"
-			>`, nil},
-		{"clib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "//clib:c.ts"
-			>
-			attribute: <
-				type: 5
-				name: "tags"
-				string_list_value: "alt_dep=//d:dlib"
-			>`, []string{"b/c"}},
-	}, []*file{{"x.ts", []string{"import x from 'b/c';"}}})
-	if r == nil {
-		t.FailNow()
-	}
-	if diff := pretty.Compare(missingDeps(r[0]), []string{"//d:dlib"}); diff != "" {
-		t.Fatalf("Analyze: failed to detect missing dependencies: (-got, +want)\n%s", diff)
-	}
-}
-
-func TestCircularImport(t *testing.T) {
-	r := analyzeTargets(t, []string{"a_lib"}, []*testTarget{
-		{"a_lib", `
-			rule_class: "ts_library"
-			attribute: <
-				type: 5
-				name: "srcs"
-				string_list_value: "f1.ts"
-				string_list_value: "f2.ts"
-			>`, []string{"a/f1", "a/f2"}},
-	}, []*file{
-		{"f1.ts", []string{"import {x} from 'a/f1';", "export let y = x + 1;"}},
-		{"f2.ts", []string{"import {y} from 'a/f2';", "export let x = y + 0;"}},
-	})
-	if r == nil {
-		t.FailNow()
-	}
-	if diff := pretty.Compare(missingDeps(r[0]), []string{}); diff != "" {
-		t.Fatalf("Analyze: failed to detect missing dependencies: (-got, +want)\n%s", diff)
-	}
-}
-
-func TestListAttribute(t *testing.T) {
-	tests := []struct {
-		name  string
-		value []string
-	}{
-		{"srcs", []string{"a.ts", "b.ts"}},
-		{"deps", []string{":core"}},
-	}
-	result, err := createResult(`
-		target: <
-			type: 1
-			rule: <
-				name: "//tmp:tmp"
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "srcs"
-					string_list_value: "a.ts"
-					string_list_value: "b.ts"
-				>
-				attribute: <
-					type: 5
-					name: "deps"
-					string_list_value: ":core"
-				>
-			>
-		>`)
-	if err != nil {
-		t.Fatalf("failed to create result: %q", err)
-	}
-	for _, test := range tests {
-		attrValue := listAttribute(result.GetTarget()[0].GetRule(), test.name)
-		if attrValue == nil {
-			t.Errorf("listAttribute(%q): failed to find attribute", test.name)
-			continue
-		}
-		if diff := pretty.Compare(attrValue, test.value); diff != "" {
-			t.Errorf("listAttribute(%q): failed to get correct attribute values: (-got, +want)\n%s", test.name, diff)
-		}
-	}
-}
-
-func TestStringAttribute(t *testing.T) {
-	tests := []struct {
-		name, value string
-	}{
-		{"module_name", "@angular/core"},
-		{"module_root", ""},
-	}
-	result, err := createResult(`
-		target: <
-			type: 1
-			rule: <
-				name: "//tmp:tmp"
-				rule_class: "ts_library"
-				attribute: <
-					type: 5
-					name: "module_name"
-					string_value: "@angular/core"
-				>
-			>
-		>`)
-	if err != nil {
-		t.Fatalf("failed to create result: %q", err)
-	}
-	for _, test := range tests {
-		attrValue := stringAttribute(result.GetTarget()[0].GetRule(), test.name)
-		if diff := pretty.Compare(attrValue, test.value); diff != "" {
-			t.Errorf("stringAttribute(%q): failed to get correct attribute values: (-got, +want)\n%s", test.name, diff)
-		}
-	}
-}
-
-func TestSetSources(t *testing.T) {
-	tests := []struct {
-		name                   string
-		srcs                   []string
-		loadedSrcs             map[string]*appb.Target
-		err                    error
-		expected               map[string]*appb.Target
-		expectedLiteralPaths   []string
-		expectedGeneratedPaths []string
-	}{
-		{
-			"NoSources",
-			nil,
-			nil,
-			nil,
-			nil,
-			nil,
-			nil,
-		},
-		{
-			"OneSource",
-			[]string{"//a:file.ts"},
-			map[string]*appb.Target{
-				"//a:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-			},
-			nil,
-			map[string]*appb.Target{
-				"//a:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-			},
-			[]string{"a/file.ts"},
-			nil,
-		},
-		{
-			"ExtraSources",
-			[]string{"//a:file.ts"},
-			map[string]*appb.Target{
-				"//a:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:generator": &appb.Target{Type: appb.Target_RULE.Enum()},
-				"//b:wiz":       &appb.Target{Type: appb.Target_RULE.Enum()},
-			},
-			nil,
-			map[string]*appb.Target{
-				"//a:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-			},
-			[]string{"a/file.ts"},
-			nil,
-		},
-		{
-			"MultipleLiteralSources",
-			[]string{"//a:file.ts", "//b:file.ts"},
-			map[string]*appb.Target{
-				"//a:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-			},
-			nil,
-			map[string]*appb.Target{
-				"//a:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:file.ts": &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-			},
-			[]string{"a/file.ts", "b/file.ts"},
-			nil,
-		},
-		{
-			"MultipleGeneratedSources",
-			[]string{"//b:generator", "//b:wiz"},
-			map[string]*appb.Target{
-				"//b:generator": &appb.Target{Type: appb.Target_RULE.Enum()},
-				"//b:wiz":       &appb.Target{Type: appb.Target_RULE.Enum()},
-			},
-			fmt.Errorf("rule has generated sources - cannot determine dependencies"),
-			nil,
-			nil,
-			nil,
-		},
-		{
-			"MixedSources",
-			[]string{"//a:file.ts", "//b:file.ts", "//b:generator", "//b:wiz"},
-			map[string]*appb.Target{
-				"//a:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:generator": &appb.Target{Type: appb.Target_RULE.Enum()},
-				"//b:wiz":       &appb.Target{Type: appb.Target_RULE.Enum()},
-			},
-			nil,
-			map[string]*appb.Target{
-				"//a:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:file.ts":   &appb.Target{Type: appb.Target_SOURCE_FILE.Enum()},
-				"//b:generator": &appb.Target{Type: appb.Target_RULE.Enum()},
-				"//b:wiz":       &appb.Target{Type: appb.Target_RULE.Enum()},
-			},
-			[]string{"a/file.ts", "b/file.ts"},
-			[]string{"//b:generator", "//b:wiz"},
-		},
-		{
-			"MissingSources",
-			[]string{"//a:file.ts"},
-			nil,
-			fmt.Errorf("no source found for label %s", "//a:file.ts"),
-			nil,
-			nil,
-			nil,
-		},
-	}
-
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			rt := &resolvedTarget{
-				rule: &appb.Rule{
-					Attribute: []*appb.Attribute{
-						&appb.Attribute{
-							Name:            proto.String("srcs"),
-							Type:            appb.Attribute_STRING_LIST.Enum(),
-							StringListValue: test.srcs,
-						},
-					},
-				},
-				sources: make(map[string]*appb.Target),
-			}
-
-			err := rt.setSources(test.loadedSrcs)
-			if !reflect.DeepEqual(err, test.err) {
-				t.Errorf("got err %q, expected %q", err, test.err)
-			}
-
-			if diff := cmp.Diff(rt.sources, test.expected, cmpopts.EquateEmpty(), cmp.Comparer(proto.Equal)); err == nil && diff != "" {
-				t.Errorf("failed to set correct sources: (-got, +want)\n%s", diff)
-			}
-		})
-	}
-}
-
-func missingDeps(report *arpb.DependencyReport) []string {
-	var deps []string
-	for _, group := range report.GetMissingDependencyGroup() {
-		deps = append(deps, group.GetDependency()...)
-	}
-	return deps
-}
-
-func createResult(str string) (*appb.QueryResult, error) {
-	var result appb.QueryResult
-	return &result, proto.UnmarshalText(strings.Trim(str, " \n\r\t"), &result)
-}
-
-func createFile(path string, content ...string) error {
-	if !filepath.IsAbs(path) {
-		path = filepath.Join(filepath.Dir(testTmpDir), path)
-	}
-	if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
-		return err
-	}
-	return ioutil.WriteFile(path, []byte(strings.Join(content, "\n")), 0666)
-}
-
-// This method creates a WORKSPACE file in the root of the Bazel test
-// directory. This allows the tests to resolve the root path of the
-// workspace by looking for the WORKSPACE file on disk.
-func createWorkspaceFile() error {
-	path := filepath.Join(filepath.Dir(testTmpDir), "WORKSPACE")
-	return ioutil.WriteFile(path, []byte("workspace(name = 'foo')"), 0666)
-}
diff --git a/ts_auto_deps/analyze/imports.go b/ts_auto_deps/analyze/imports.go
deleted file mode 100644
index 28f6501..0000000
--- a/ts_auto_deps/analyze/imports.go
+++ /dev/null
@@ -1,150 +0,0 @@
-package analyze
-
-import (
-	"io/ioutil"
-	"path/filepath"
-	"regexp"
-	"strings"
-	"sync"
-
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/workspace"
-)
-
-// ts_auto_depsImport represents a single import in a TypeScript source.
-type ts_auto_depsImport struct {
-	// importPath can be an ES6 path ('./foo/bar'), but also a namespace ('goog:...').
-	// This is the import path as it appears in the TypeScript source.
-	importPath string
-	// knownTarget is the (fully qualified) bazel target providing importPath.
-	// It's either found by locateMissingTargets or taken from a ts_auto_deps comment.
-	knownTarget string
-	location    sourceLocation
-}
-
-// resolvedPath is the path to the import relative to the root of the
-// workspace. For example, an import of './foo' in the 'bar/baz' directory
-// would have a path from root of 'bar/baz/foo'.
-//
-// Absolute imports have no resolvedPath since the physical location of
-// these imports depends on the dependencies of the target the source
-// location is a member of. For example, an import of 'foo/bar' would have
-// no resolvedPath.
-func (i *ts_auto_depsImport) resolvedPath() string {
-	if strings.HasPrefix(i.importPath, "./") || strings.HasPrefix(i.importPath, "../") {
-		// If the import is relative to the source location, use the source
-		// location to form a "canonical" path from the root.
-		return platform.Normalize(filepath.Clean(filepath.Join(filepath.Dir(i.location.sourcePath), i.importPath)))
-	} else if trim := strings.TrimPrefix(i.importPath, workspace.Name()+"/"); trim != i.importPath {
-		return trim
-	}
-	// The import is an absolute import and therefore does not have a definite
-	// resolved path.
-	return i.importPath
-}
-
-// sourceLocation points to a position in a source file.
-type sourceLocation struct {
-	// Workspace root relative source path.
-	sourcePath string
-	// offset and length are byte offsets, line is the 1-indexed source line (considering only \n as breaks).
-	offset, length, line int
-}
-
-// extractAllImports extracts the TypeScript imports from paths.
-//
-// paths should be relative to root. The root will be joined to each path
-// to construct a physical path to each file.
-func extractAllImports(root string, paths []string) (map[string][]*ts_auto_depsImport, []error) {
-	debugf("extracting imports from TypeScript files relative to %q: %q", root, paths)
-	allImports := make(map[string][]*ts_auto_depsImport)
-	var (
-		errors []error
-		mutex  sync.Mutex
-		group  sync.WaitGroup
-	)
-	for _, path := range paths {
-		group.Add(1)
-		go func(path string) {
-			defer group.Done()
-			imports, err := extractImports(root, path)
-			// Lock the mutex to prevent concurrent writes.
-			mutex.Lock()
-			defer mutex.Unlock()
-			if err != nil {
-				errors = append(errors, err)
-				return
-			}
-			allImports[path] = imports
-		}(path)
-	}
-	group.Wait()
-	return allImports, errors
-}
-
-// extractImports extracts the TypeScript imports from a single file. path
-// should be a path from the root to the file.
-func extractImports(root, path string) ([]*ts_auto_depsImport, error) {
-	d, err := ioutil.ReadFile(filepath.Join(root, path))
-	if err != nil {
-		return nil, err
-	}
-	return parseImports(path, d), nil
-}
-
-const (
-	ts_auto_depsFrom  = `^[ \t]*//[ \t]+ts_auto_deps:[^\n]*?from[ \t]+(?P<Target>//\S+)$`
-	importPreface     = `^[ \t]*(?:import|export)\b\s*`
-	wildcardTerm      = `\*(?:\s*as\s+\S+)?` // "as..." is optional to match exports.
-	identifiersClause = `(?:\{[^}]*\}|\S+|` + wildcardTerm + `)`
-	symbolsTerm       = `(?:` + identifiersClause + `(?:,\s*` + identifiersClause + `)?\s*\bfrom\b\s*)?`
-	url               = `['"](?P<URL>[^'";]+)['"]\s*;?`
-	namespaceComment  = `(?:\s*//[ \t]*from[ \t]+(?P<Target>//\S+)$)?`
-)
-
-var importRE = regexp.MustCompile("(?ms)" +
-	"(?:" + ts_auto_depsFrom + ")|" +
-	"(?:" + importPreface + symbolsTerm + url + namespaceComment + ")")
-
-// parseImports scans contents for imports (ES6 modules, ts_auto_deps comments), and
-// returns a list of ts_auto_depsImports. knownTarget is already filled in for imports
-// that have ts_auto_deps comments.
-func parseImports(sourcePath string, contents []byte) []*ts_auto_depsImport {
-	var imports []*ts_auto_depsImport
-	lastOffset := 0
-	line := 1
-	column := 1
-	for _, matchIndices := range importRE.FindAllSubmatchIndex(contents, -1) {
-		imp := &ts_auto_depsImport{}
-		imports = append(imports, imp)
-		// matchIndices[0, 1]: full RE match
-		imp.location.sourcePath = sourcePath
-		for lastOffset < matchIndices[1] {
-			// Iterate to the *end* of the import statement.
-			// The ts_auto_deps comment must be placed at the end of the "import" statement.
-			// This offset has to be exactly the end of the import for ts_auto_deps later on
-			// to insert the '// from' comment in the correct line.
-			column++
-			if contents[lastOffset] == '\n' {
-				line++
-				column = 1
-			}
-			lastOffset++
-		}
-		imp.location.offset = matchIndices[0]
-		imp.location.length = matchIndices[1] - matchIndices[0]
-		imp.location.line = line
-		if matchIndices[2] >= 0 {
-			// matchIndices[2, 3]: Target for a // ts_auto_deps: ... from ... comment.
-			imp.knownTarget = string(contents[matchIndices[2]:matchIndices[3]])
-		} else {
-			// matchIndices[4, 5]: URL in import x from 'url';
-			imp.importPath = string(contents[matchIndices[4]:matchIndices[5]])
-		}
-		if matchIndices[6] >= 0 {
-			// matchIndices[6, 7]: Target for a // from comment
-			imp.knownTarget = string(contents[matchIndices[6]:matchIndices[7]])
-		}
-	}
-	return imports
-}
diff --git a/ts_auto_deps/analyze/imports_test.go b/ts_auto_deps/analyze/imports_test.go
deleted file mode 100644
index 029df0e..0000000
--- a/ts_auto_deps/analyze/imports_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package analyze
-
-import (
-	"fmt"
-	"testing"
-
-	"github.com/kylelemons/godebug/pretty"
-)
-
-func TestParseImports(t *testing.T) {
-	tests := []struct{ text, importPath, knownTarget string }{
-		// Imports
-		{"import {a} from 'named';", "named", ""},
-		{"code before;\n import {a} from 'before after'; code after",
-			"before after", ""},
-		{"import A from 'default';", "default", ""},
-		{"import A$X from 'default';", "default", ""},
-		{"import {x as $} from 'default';", "default", ""},
-		{"import ü from 'default';", "default", ""},
-		{"import * as prefix from 'wildcard prefixed';", "wildcard prefixed", ""},
-		{" \t import {A, B as C} from 'renamed';", "renamed", ""},
-		{"import 'sideeffect import';", "sideeffect import", ""},
-		{"import\n {A\n, B} from 'newlines';", "newlines", ""},
-		{"import*as prefix from'no whitespace';", "no whitespace", ""},
-		{"import Symbol from 'goog:some.Symbol';  // from //target:location",
-			"goog:some.Symbol", "//target:location"},
-		{"import Symbol from 'goog:some.Symbol';//from  //target:location",
-			"goog:some.Symbol", "//target:location"},
-		{"import {a} from 'missing semi'", "missing semi", ""},
-		{"import {a} from 'missing semi' // from //target:location",
-			"missing semi", "//target:location"},
-		{"import A, {B, C} from 'mixed';", "mixed", ""},
-		{"import A, * as B from 'mixed';", "mixed", ""},
-		{"import * as B, A from 'inverted mixed';", "inverted mixed", ""},
-		// Exports
-		{"export * from 'wildcard';", "wildcard", ""},
-		{"export {a, b} from 'named';", "named", ""},
-		{"export {} from 'empty import';", "empty import", ""},
-		{"export {a as b} from 'renamed';", "renamed", ""},
-		{"export\n {A\n, B} from 'newlines';", "newlines", ""},
-		{"export*from'no whitespace';", "no whitespace", ""},
-		{"export{}from'no whitespace';", "no whitespace", ""},
-		// Comments
-		{"x;\n// ts_auto_deps: ng from //some/global:rule\ny;", "", "//some/global:rule"},
-		{"// ts_auto_deps: ng from //foo/bar from //some/global:rule", "", "//some/global:rule"},
-	}
-
-	for i, tst := range tests {
-		imports := parseImports(fmt.Sprintf("test%d.ts", i), []byte(tst.text))
-		if len(imports) != 1 {
-			t.Errorf("parseImports(%q): got %d import(s), want 1", tst.text, len(imports))
-			continue
-		}
-		imp := imports[0]
-		if imp.importPath != tst.importPath {
-			t.Errorf("parseImports(%q): got %q, want %q", tst.text, imp.importPath, tst.importPath)
-		}
-		if imp.knownTarget != tst.knownTarget {
-			t.Errorf("parseImports(%q): got %q, want %q", tst.text, imp.knownTarget, tst.knownTarget)
-		}
-	}
-}
-
-func TestParseImportsSourceLocation(t *testing.T) {
-	tests := []struct {
-		text                   string
-		expectedSourceLocation sourceLocation
-	}{
-		{"import {a} from 'named';", sourceLocation{line: 1, offset: 0, length: 24}},
-		{"\n\timport {a} from 'named';", sourceLocation{line: 2, offset: 1, length: 25}},
-	}
-	for i, tst := range tests {
-		sourcePath := fmt.Sprintf("test%d.ts", i)
-		imports := parseImports(sourcePath, []byte(tst.text))
-		if len(imports) != 1 {
-			t.Errorf("parseImports(%q): got %d import(s), want 1", tst.text, len(imports))
-			continue
-		}
-		imp := imports[0]
-		tst.expectedSourceLocation.sourcePath = sourcePath
-		if diff := pretty.Compare(imp.location, tst.expectedSourceLocation); diff != "" {
-			t.Errorf("parseImports(%q): expected different source location: (-got, +want)\n%s", tst.text, diff)
-		}
-	}
-}
diff --git a/ts_auto_deps/analyze/loader.go b/ts_auto_deps/analyze/loader.go
deleted file mode 100644
index 4a98600..0000000
--- a/ts_auto_deps/analyze/loader.go
+++ /dev/null
@@ -1,737 +0,0 @@
-package analyze
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"os/exec"
-	"path/filepath"
-	"strings"
-	"time"
-
-	"github.com/bazelbuild/buildtools/edit"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/workspace"
-	"github.com/golang/protobuf/proto"
-
-	appb "github.com/bazelbuild/buildtools/build_proto"
-)
-
-// pkgCacheEntry represents a set of loaded rules and a mapping from alias
-// to rules from a package.
-type pkgCacheEntry struct {
-	// rules is all rules in a package.
-	rules []*appb.Rule
-	// aliases is a map from an alias label to the actual rule of the alias.
-	aliases map[string]*appb.Rule
-}
-
-// QueryBasedTargetLoader uses Bazel query to load targets from BUILD files.
-type QueryBasedTargetLoader struct {
-	workdir     string
-	bazelBinary string
-
-	// pkgCache is a mapping from a package to all of the rules in said
-	// package along with a map from aliases to actual rules.
-	//
-	// Keys are of the form of "<visibility>|<package>" where visibility
-	// is the package that rules in package must be visible to and package
-	// is the actual package that has been loaded and cached.
-	//
-	// Since a new target loader is constructed for each directory being
-	// analyzed in the "-recursive" case, these caches will be garbage
-	// collected between directories.
-	pkgCache map[string]*pkgCacheEntry
-	// labelCache is a mapping from a label to its loaded target.
-	labelCache map[string]*appb.Target
-
-	// queryCount is the total number of queries executed by the target loader.
-	queryCount int
-}
-
-// NewQueryBasedTargetLoader constructs a new QueryBasedTargetLoader rooted
-// in workdir.
-func NewQueryBasedTargetLoader(workdir, bazelBinary string) *QueryBasedTargetLoader {
-	return &QueryBasedTargetLoader{
-		workdir:     workdir,
-		bazelBinary: bazelBinary,
-
-		pkgCache:   make(map[string]*pkgCacheEntry),
-		labelCache: make(map[string]*appb.Target),
-	}
-}
-
-// LoadRules uses Bazel query to load rules associated with labels from BUILD
-// files.
-func (q *QueryBasedTargetLoader) LoadRules(pkg string, labels []string) (map[string]*appb.Rule, error) {
-	labelToTarget, err := q.LoadTargets(pkg, labels)
-	if err != nil {
-		return nil, err
-	}
-
-	labelToRule := make(map[string]*appb.Rule)
-	for _, label := range labels {
-		target := labelToTarget[label]
-		if target.GetType() == appb.Target_RULE {
-			labelToRule[label] = target.GetRule()
-		} else {
-			return nil, fmt.Errorf("target %s contains object of type %q instead of type %q", label, target.GetType(), appb.Target_RULE)
-		}
-	}
-	return labelToRule, nil
-}
-
-// LoadTargets uses Bazel query to load targets associated with labels from BUILD
-// files.
-func (q *QueryBasedTargetLoader) LoadTargets(pkg string, labels []string) (map[string]*appb.Target, error) {
-	var labelCacheMisses []string
-	for _, label := range labels {
-		if _, ok := q.labelCache[labelCacheKey(pkg, label)]; !ok {
-			labelCacheMisses = append(labelCacheMisses, label)
-		}
-	}
-	if len(labelCacheMisses) > 0 {
-		var queries []string
-		if pkg == "" {
-			queries = labelCacheMisses
-		} else {
-			for _, label := range labelCacheMisses {
-				queries = append(queries, fmt.Sprintf("visible(%s:*, %s)", pkg, label))
-			}
-		}
-		r, err := q.batchQuery(queries)
-		if err != nil {
-			return nil, err
-		}
-		for _, target := range r.GetTarget() {
-			label, err := q.targetLabel(target)
-			if err != nil {
-				return nil, err
-			}
-			q.labelCache[labelCacheKey(pkg, label)] = target
-		}
-		for _, label := range labelCacheMisses {
-			key := labelCacheKey(pkg, label)
-			if _, ok := q.labelCache[key]; !ok {
-				// Set to nil so the result exists in the cache and is not
-				// loaded again. If the nil is not added at the appropriate
-				// cache key, LoadLabels will attempt to load it again when
-				// next requested instead of getting a cache hit.
-				q.labelCache[key] = nil
-			}
-		}
-	}
-	labelToTarget := make(map[string]*appb.Target)
-	for _, label := range labels {
-		labelToTarget[label] = q.labelCache[labelCacheKey(pkg, label)]
-	}
-	return labelToTarget, nil
-}
-
-func labelCacheKey(currentPkg, label string) string {
-	return currentPkg + "^" + label
-}
-
-// possibleFilepaths generates the possible filepaths for the ts import path.
-// e.g. google3/foo/bar could be foo/bar.ts or foo/bar.d.ts or foo/bar/index.ts, etc.
-// Also handles special angular import paths (.ngfactory and .ngsummary).
-func possibleFilepaths(importPath string) []string {
-	// If the path has a suffix of ".ngfactory" or ".ngsummary", it might
-	// be an Angular AOT generated file. We can infer the target as we
-	// infer its corresponding ngmodule target by simply stripping the
-	// ".ngfactory" / ".ngsummary" suffix
-	importPath = strings.TrimSuffix(strings.TrimSuffix(importPath, ".ngsummary"), ".ngfactory")
-	importPath = strings.TrimPrefix(importPath, workspace.Name()+"/")
-
-	var possiblePaths []string
-
-	possiblePaths = append(possiblePaths, pathWithExtensions(importPath)...)
-	possiblePaths = append(possiblePaths, pathWithExtensions(filepath.Join(importPath, "index"))...)
-
-	return possiblePaths
-}
-
-// LoadImportPaths uses Bazel Query to load targets associated with import
-// paths from BUILD files.
-func (q *QueryBasedTargetLoader) LoadImportPaths(ctx context.Context, targetToAnalyze *appb.Rule, currentPkg, workspaceRoot string, paths []string) (map[string]*appb.Rule, error) {
-	debugf("loading imports visible to %q relative to %q: %q", currentPkg, workspaceRoot, paths)
-	results := make(map[string]*appb.Rule)
-
-	addedPaths := make(map[string]bool)
-	var possibleFilePaths []string
-	possiblePathToPaths := make(map[string][]string)
-	// for all the normalized typescript import paths, generate all the possible
-	// corresponding file paths
-	for _, path := range paths {
-		if strings.HasPrefix(path, "goog:") {
-			// 'goog:' imports are resolved using an sstable.
-			results[path] = nil
-			continue
-		}
-		if strings.HasPrefix(path, "@") {
-			continue
-		}
-
-		if _, ok := addedPaths[path]; !ok {
-			addedPaths[path] = true
-
-			// there isn't a one to one mapping from ts import paths to file
-			// paths, so look for all the possible file paths
-			pfs := possibleFilepaths(path)
-			possibleFilePaths = append(possibleFilePaths, pfs...)
-			// map the file paths back to the import paths so we can map the file
-			// labels back to the import paths
-			for _, pf := range pfs {
-				possiblePathToPaths[pf] = append(possiblePathToPaths[pf], path)
-			}
-		}
-	}
-
-	// query for all the possible filepaths, to determine which ones are real
-	r, err := q.batchQuery(possibleFilePaths)
-	if err != nil {
-		return nil, err
-	}
-	var fileLabels, packages []string
-	fileToGeneratorLabel := make(map[string]string)
-	pathToLabels := make(map[string][]string)
-	// get the labels for all the files which exist
-	for _, target := range r.GetTarget() {
-		label, err := q.fileLabel(target)
-		if err != nil {
-			return nil, err
-		}
-		switch target.GetType() {
-		case appb.Target_GENERATED_FILE:
-			file := target.GetGeneratedFile()
-			generator := file.GetGeneratingRule()
-			label = file.GetName()
-
-			fileLabels = append(fileLabels, label)
-			_, pkg, _ := edit.ParseLabel(label)
-			packages = append(packages, pkg)
-			// a generated file can be included as a source by referencing the label
-			// of the generated file, or the label of the generating rule, so check
-			// for both
-			fileToGeneratorLabel[labelToPath(label)] = labelToPath(generator)
-			// map file label back to the import paths so that they can be looked for
-			// in the srcs of the rules
-			for _, path := range possiblePathToPaths[labelToPath(label)] {
-				pathToLabels[path] = append(pathToLabels[path], label)
-			}
-		case appb.Target_SOURCE_FILE:
-			fileLabels = append(fileLabels, label)
-			_, pkg, _ := edit.ParseLabel(label)
-			packages = append(packages, pkg)
-			// map file label back to the import paths so that they can be looked for
-			// in the srcs of the rules
-			for _, path := range possiblePathToPaths[labelToPath(label)] {
-				pathToLabels[path] = append(pathToLabels[path], label)
-			}
-		}
-	}
-
-	// load all the rules in all the packages files were found in, so we can look
-	// for aliases and reexporting libraries in the same package
-	pkgToAllRules, pkgToActualToAlias, err := q.loadAllRulesInPackages("", packages)
-	if err != nil {
-		return nil, err
-	}
-
-	for _, path := range paths {
-		// look up the corresponding file label(s) for the normalized typescript
-		// import path
-		for _, label := range pathToLabels[path] {
-			_, pkg, _ := edit.ParseLabel(label)
-			// get the file path that corresponds to the normalized typescript import
-			// path
-			filePath := labelToPath(label)
-			allRules := pkgToAllRules[pkg]
-			actualToAlias := pkgToActualToAlias[pkg]
-			var matchingDeps []*appb.Rule
-			for _, candidate := range typeScriptRules(allRules) {
-				// check if the rule has the file or the generator of the file in its
-				// srcs
-				possibleSources := []string{filePath}
-				if gl, ok := fileToGeneratorLabel[filePath]; ok {
-					possibleSources = append(possibleSources, gl)
-				}
-				provides, err := q.ruleProvidesImports(candidate, srcsContainsAnyFilePath(possibleSources))
-				if err != nil {
-					return nil, err
-				}
-				if !provides {
-					continue
-				}
-
-				if alias, ok := actualToAlias[candidate.GetName()]; ok {
-					candidate = alias
-				}
-				matchingDeps = append(matchingDeps, candidate)
-			}
-			if len(matchingDeps) > 0 {
-				canonicalRule, err := q.chooseCanonicalDep(currentPkg, targetToAnalyze, matchingDeps)
-				if err != nil {
-					return nil, err
-				}
-				results[path] = canonicalRule
-			}
-		}
-	}
-
-	return results, nil
-}
-
-// chooseCanonicalDep chooses between rules which include the imported file as
-// a source (ie the rule that includes the file as a src, and any reexporting
-// libraries).
-//
-// It filters the rules in a 3 stage process:
-//
-// 1. If only one of the rules is visible, choose that one, since the rule
-// creator intended it to be imported.
-//
-// 2. If all or none of the rules are visible, choose the rule that directly
-// includes the file as a src, since that reduces the chance of introducing
-// circular dependencies.
-//
-// 3. Choose the rule that is already included as a dep.
-func (q *QueryBasedTargetLoader) chooseCanonicalDep(currentPkg string, targetToAnalyze *appb.Rule, deps []*appb.Rule) (*appb.Rule, error) {
-	// check for visibility
-	filterForVisibility := func(deps []*appb.Rule) ([]*appb.Rule, error) {
-		var labels []string
-		for _, d := range deps {
-			labels = append(labels, d.GetName())
-		}
-		visibleDepsMap, err := q.LoadRules(currentPkg, labels)
-		if err != nil {
-			return nil, err
-		}
-
-		var visibleDeps []*appb.Rule
-		for _, d := range visibleDepsMap {
-			if d != nil {
-				visibleDeps = append(visibleDeps, d)
-			}
-		}
-
-		return visibleDeps, nil
-	}
-
-	// if there's a visible reexporting lib and a visible lib with the src, favor
-	// the lib with the src, to reduce the chance of introducing a circular
-	// dependency
-	filterForBaseLibs := func(deps []*appb.Rule) ([]*appb.Rule, error) {
-		var baseDeps []*appb.Rule
-		for _, d := range deps {
-			if !isReexportingLib(d) {
-				baseDeps = append(baseDeps, d)
-			}
-		}
-
-		return baseDeps, nil
-	}
-
-	// favor the dep that's already on the rule
-	filterForExistingDeps := func(deps []*appb.Rule) ([]*appb.Rule, error) {
-		var existingDeps []*appb.Rule
-		for _, d := range deps {
-			for _, existing := range listAttribute(targetToAnalyze, "deps") {
-				if d.GetName() == existing {
-					existingDeps = append(existingDeps, d)
-				}
-			}
-		}
-
-		return existingDeps, nil
-	}
-
-	filters := []func(deps []*appb.Rule) ([]*appb.Rule, error){
-		filterForVisibility,
-		filterForBaseLibs,
-		filterForExistingDeps,
-	}
-
-	// for each filter, return if it returned a single rule, narrow the set of deps if
-	// it discarded some, but not all, and try the full set with the next filter if it
-	// discarded them all
-	for _, filter := range filters {
-		filteredDeps, err := filter(deps)
-		if err != nil {
-			return nil, err
-		}
-		if len(filteredDeps) == 1 {
-			return filteredDeps[0], nil
-		} else if len(filteredDeps) > 0 {
-			deps = filteredDeps
-		}
-	}
-
-	// no filter got down to a single rule, just return the first
-	return deps[0], nil
-}
-
-// ruleLabel returns the label for a target which is a rule.  Returns an error if
-// target is not a rule.
-func (q *QueryBasedTargetLoader) ruleLabel(target *appb.Target) (string, error) {
-	if t := target.GetType(); t != appb.Target_RULE {
-		return "", fmt.Errorf("target contains object of type %q instead of type %q", t, appb.Target_RULE)
-	}
-	return target.GetRule().GetName(), nil
-}
-
-// fileLabel returns the label for a target which is a file.  Returns an error if
-// target is not a source file or a generated file.
-func (q *QueryBasedTargetLoader) fileLabel(target *appb.Target) (string, error) {
-	switch t := target.GetType(); t {
-	case appb.Target_GENERATED_FILE:
-		return target.GetGeneratedFile().GetName(), nil
-	case appb.Target_SOURCE_FILE:
-		return target.GetSourceFile().GetName(), nil
-	default:
-		return "", fmt.Errorf("target contains object of type %q instead of type %q or %q", t, appb.Target_SOURCE_FILE, appb.Target_GENERATED_FILE)
-	}
-}
-
-// targetLabel returns the label for a target.  Returns an error if target is an
-// unknown type.
-func (q *QueryBasedTargetLoader) targetLabel(target *appb.Target) (string, error) {
-	switch t := target.GetType(); t {
-	case appb.Target_GENERATED_FILE:
-		return target.GetGeneratedFile().GetName(), nil
-	case appb.Target_SOURCE_FILE:
-		return target.GetSourceFile().GetName(), nil
-	case appb.Target_RULE:
-		return target.GetRule().GetName(), nil
-	case appb.Target_PACKAGE_GROUP:
-		return target.GetPackageGroup().GetName(), nil
-	case appb.Target_ENVIRONMENT_GROUP:
-		return target.GetEnvironmentGroup().GetName(), nil
-	default:
-		return "", fmt.Errorf("target contains object of unknown type %q", t)
-	}
-}
-
-// batchQuery runs a set of queries with a single call to Bazel query and the
-// '--keep_going' flag.
-func (q *QueryBasedTargetLoader) batchQuery(queries []string) (*appb.QueryResult, error) {
-	// Join all of the queries with a '+' character according to Bazel's
-	// syntax for running multiple queries.
-	return q.query("--keep_going", strings.Join(queries, "+"))
-}
-
-func (q *QueryBasedTargetLoader) query(args ...string) (*appb.QueryResult, error) {
-	n := len(args)
-	if n < 1 {
-		return nil, fmt.Errorf("expected at least one argument")
-	}
-	query := args[n-1]
-	if query == "" {
-		// An empty query was provided so return an empty result without
-		// making a call to Bazel.
-		return &appb.QueryResult{}, nil
-	}
-	var stdout, stderr bytes.Buffer
-	args = append([]string{"query", "--output=proto"}, args...)
-	q.queryCount++
-	debugf("executing query #%d in %q: %s %s %q", q.queryCount, q.workdir, q.bazelBinary, strings.Join(args[:len(args)-1], " "), query)
-	cmd := exec.Command(q.bazelBinary, args...)
-	cmd.Dir = q.workdir
-	cmd.Stdout = &stdout
-	cmd.Stderr = &stderr
-	startTime := time.Now()
-	if err := cmd.Run(); err != nil {
-		// Exit status 3 is a direct result of one or more queries in a set of
-		// queries not returning a result while running with the '--keep_going'
-		// flag. Since one query failing to return a result does not hinder the
-		// other queries from returning a result, ignore these errors.
-		//
-		// Herb prints "printing partial results" to indicate the same as bazel's
-		// exit status 3
-		if err.Error() != "exit status 3" && !strings.Contains(stderr.String(), "printing partial results") {
-			// The error provided as a result is less useful than the contents of
-			// stderr for debugging.
-			return nil, fmt.Errorf(stderr.String())
-		}
-	}
-	debugf("query #%d took %v", q.queryCount, time.Since(startTime))
-	var result appb.QueryResult
-	if err := proto.Unmarshal(stdout.Bytes(), &result); err != nil {
-		return nil, err
-	}
-	return &result, nil
-}
-
-// ruleProvidesImports checks if the rule directly provides the import, or if
-// it's a reexporting lib, if one of its deps does.
-func (q *QueryBasedTargetLoader) ruleProvidesImports(rule *appb.Rule, srcMatcher func(rule *appb.Rule) bool) (bool, error) {
-	if srcMatcher(rule) {
-		return true, nil
-	}
-
-	if !isReexportingLib(rule) {
-		return false, nil
-	}
-
-	// if the rule is a reexporting library, load all the rules that the rule
-	// reexports, and check if they provide the imported paths.  This only handles
-	// one level of reexport.
-	_, pkg, _ := edit.ParseLabel(rule.GetName())
-	// TODO(alexeagle): Batch calls to LoadLabels. Batching calls to ruleProvidesImport
-	// would also be required.
-	exportedRules, err := q.LoadRules(pkg, exportedLabels(rule))
-	if err != nil {
-		return false, err
-	}
-	for _, exportedRule := range exportedRules {
-		if srcMatcher(exportedRule) {
-			return true, nil
-		}
-	}
-
-	return false, nil
-}
-
-// exportedLabels returns the labels exported by rule. Exported labels are the
-// deps of a rule if the rule is an alias.
-func exportedLabels(rule *appb.Rule) []string {
-	var exported []string
-	if isReexportingLib(rule) {
-		exported = append(exported, listAttribute(rule, "deps")...)
-	}
-	return exported
-}
-
-// isReexportingLib checks if a library has no sources, which the TS rules use a
-// way to mark a library as an alias.
-func isReexportingLib(rule *appb.Rule) bool {
-	return len(listAttribute(rule, "srcs")) == 0
-}
-
-// srcsContainsPath returns a function, which takes a rule, which returns true
-// if the rule has a src which matches one of the possible filepaths for the
-// provided typescript import path.
-func srcsContainsPath(path string) func(rule *appb.Rule) bool {
-	return func(rule *appb.Rule) bool {
-		resolvedImportPath := resolveAgainstModuleRoot(rule, path)
-
-		// enumerate all the possible filepaths for the resolved import path, and
-		// compare against all the srcs
-		possibleImportPaths := possibleFilepaths(resolvedImportPath)
-		for _, src := range listAttribute(rule, "srcs") {
-			for _, mi := range possibleImportPaths {
-				if mi == labelToPath(src) {
-					return true
-				}
-			}
-		}
-
-		return false
-	}
-}
-
-// srcsContainsFilePath returns a function which takes a rule, which returns
-// true if the rule has a src which, if pathified, equals one of the filePaths.
-func srcsContainsAnyFilePath(filePaths []string) func(rule *appb.Rule) bool {
-	return func(rule *appb.Rule) bool {
-		for _, filePath := range filePaths {
-			for _, src := range listAttribute(rule, "srcs") {
-				if filePath == labelToPath(src) {
-					return true
-				}
-			}
-		}
-
-		return false
-	}
-}
-
-// loadAllRulesInPackages loads all rules in all packages.
-//
-// If an alias or aliases are present in the package, the rules for each alias'
-// 'actual' attribute are loaded and a map from each 'actual' rule to its alias
-// rule is constructed.
-//
-// loadAllRulesInPackages returns two maps. The first map is a map from a package
-// label to all of the rules in the package. The second map is a map from a
-// package to the map of 'actual' rules to alias rules for that package.
-func (q *QueryBasedTargetLoader) loadAllRulesInPackages(currentPkg string, packages []string) (map[string][]*appb.Rule, map[string]map[string]*appb.Rule, error) {
-	var missingPackages []string
-	for _, pkg := range packages {
-		if _, ok := q.pkgCache[pkgCacheKey(currentPkg, pkg)]; !ok {
-			missingPackages = append(missingPackages, pkg)
-		}
-	}
-	if len(missingPackages) > 0 {
-		// Load any packages not already available in the cache.
-		var queries []string
-		pkgToRules := make(map[string][]*appb.Rule)
-		pkgToAliasToRule := make(map[string]map[string]*appb.Rule)
-		for _, pkg := range missingPackages {
-			if currentPkg != "" {
-				queries = append(queries, fmt.Sprintf("visible(%s:*, %s:*)", currentPkg, pkg))
-			} else {
-				queries = append(queries, fmt.Sprintf("%s:*", pkg))
-			}
-			pkgToAliasToRule[pkg] = make(map[string]*appb.Rule)
-		}
-		r, err := q.batchQuery(queries)
-		if err != nil {
-			return nil, nil, err
-		}
-		actualToAlias := make(map[string]*appb.Rule)
-		pkgToActuals := make(map[string][]string)
-		for _, target := range r.GetTarget() {
-			if target.GetType() == appb.Target_RULE {
-				rule := target.GetRule()
-				_, pkg, _ := edit.ParseLabel(rule.GetName())
-				if rule.GetRuleClass() == "alias" {
-					// if the package contains an alias, derefence it (but only one layer
-					// of aliases)
-					actual := stringAttribute(rule, "actual")
-					if actual == "" {
-						// probably an alias with a select statement as the value for
-						// 'actual' - just ignore
-						platform.Infof(`alias %q has non-string "actual" attribute`, rule.GetName())
-						continue
-					}
-					actualToAlias[actual] = rule
-					pkgToActuals[pkg] = append(pkgToActuals[pkg], actual)
-				} else {
-					pkgToRules[pkg] = append(pkgToRules[pkg], rule)
-				}
-			}
-		}
-		for pkg, actuals := range pkgToActuals {
-			// Load all the aliased targets, checking if they're visible from the
-			// package where they're aliased from
-			resolvedActuals, err := q.LoadTargets(pkg, actuals)
-			if err != nil {
-				return nil, nil, err
-			}
-			for actual, target := range resolvedActuals {
-				// aliases can be for anything, but deps can only be rules, so ignore
-				// other aliased targets
-				if target.GetType() != appb.Target_RULE {
-					continue
-				}
-
-				rule := target.GetRule()
-				alias := actualToAlias[actual]
-				_, pkg, _ := edit.ParseLabel(alias.GetName())
-				pkgToAliasToRule[pkg][rule.GetName()] = alias
-				pkgToRules[pkg] = append(pkgToRules[pkg], rule)
-			}
-		}
-		for _, pkg := range missingPackages {
-			q.pkgCache[pkgCacheKey(currentPkg, pkg)] = &pkgCacheEntry{
-				rules:   pkgToRules[pkg],
-				aliases: pkgToAliasToRule[pkg],
-			}
-		}
-	}
-
-	pkgToRules := make(map[string][]*appb.Rule)
-	pkgToRuleToAlias := make(map[string]map[string]*appb.Rule)
-	for _, pkg := range packages {
-		cacheEntry := q.pkgCache[pkgCacheKey(currentPkg, pkg)]
-		pkgToRules[pkg] = cacheEntry.rules
-		pkgToRuleToAlias[pkg] = cacheEntry.aliases
-	}
-
-	return pkgToRules, pkgToRuleToAlias, nil
-}
-
-func pkgCacheKey(currentPkg, pkg string) string {
-	return currentPkg + "|" + pkg
-}
-
-// dedupeLabels returns a new set of labels with no duplicates.
-func dedupeLabels(labels []string) []string {
-	addedLabels := make(map[string]bool)
-	var uniqueLabels []string
-	for _, label := range labels {
-		if _, added := addedLabels[label]; !added {
-			addedLabels[label] = true
-			uniqueLabels = append(uniqueLabels, label)
-		}
-	}
-	return uniqueLabels
-}
-
-// typeScriptRules returns all TypeScript rules in rules.
-func typeScriptRules(rules []*appb.Rule) []*appb.Rule {
-	var tsRules []*appb.Rule
-	for _, rule := range rules {
-		for _, supportedRuleClass := range []string{
-			"ts_library",
-			"ts_declaration",
-			"ng_module",
-		} {
-			if rule.GetRuleClass() == supportedRuleClass {
-				tsRules = append(tsRules, rule)
-				break
-			}
-		}
-	}
-	return tsRules
-}
-
-// resolveAgainstModuleRoot resolves imported against moduleRoot and moduleName.
-func resolveAgainstModuleRoot(rule *appb.Rule, imported string) string {
-	moduleName := stringAttribute(rule, "module_name")
-	if moduleName == "" {
-		return imported
-	}
-	if !pathStartsWith(imported, moduleName) {
-		return imported
-	}
-	// if module root is a file, remove the file extension, since it'll be added
-	// by possibleFilepaths below
-	moduleRoot := stripTSExtension(stringAttribute(rule, "module_root"))
-	_, pkg, _ := edit.ParseLabel(rule.GetName())
-
-	// resolve the import path against the module name and module root, ie if
-	// the import path is @foo/bar and there's a moduleName of @foo the resolved
-	// import path is location/of/foo/bar, or if there's also a moduleRoot of
-	// baz, the resolved import path is location/of/foo/baz/bar
-	//
-	// using strings.TrimPrefix for trimming the path is ok, since
-	// pathStartsWith already checked that moduleName is a proper prefix of
-	// i.importPath
-	return platform.Normalize(filepath.Join(pkg, moduleRoot, strings.TrimPrefix(imported, moduleName)))
-}
-
-// pathStartsWith checks if path starts with prefix, checking each path segment,
-// so that @angular/core starts with @angular/core, but @angular/core-bananas
-// does not
-func pathStartsWith(path, prefix string) bool {
-	pathParts := strings.Split(path, "/")
-	prefixParts := strings.Split(prefix, "/")
-
-	if len(prefixParts) > len(pathParts) {
-		return false
-	}
-
-	for i, prefixPart := range prefixParts {
-		if prefixPart != pathParts[i] {
-			return false
-		}
-	}
-
-	return true
-}
-
-// parsePackageName parses and returns the scope and package of imported. For
-// example, "@foo/bar" would have a scope of "@foo" and a package of "bar".
-func parsePackageName(imported string) (string, string) {
-	firstSlash := strings.Index(imported, "/")
-	if firstSlash == -1 {
-		return imported, ""
-	}
-	afterSlash := imported[firstSlash+1:]
-	if secondSlash := strings.Index(afterSlash, "/"); secondSlash > -1 {
-		return imported[:firstSlash], afterSlash[:secondSlash]
-	}
-	return imported[:firstSlash], afterSlash
-}
diff --git a/ts_auto_deps/analyze/loader_test.go b/ts_auto_deps/analyze/loader_test.go
deleted file mode 100644
index 5765129..0000000
--- a/ts_auto_deps/analyze/loader_test.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package analyze
-
-import (
-	"testing"
-
-	"github.com/golang/protobuf/proto"
-
-	appb "github.com/bazelbuild/buildtools/build_proto"
-)
-
-func TestResolveAgainstModuleRoot(t *testing.T) {
-	tests := []struct {
-		ruleLiteral string
-		imported    string
-		expected    string
-	}{
-		{
-			ruleLiteral: `name: "//a"
-			rule_class: "ts_library"`,
-			imported: "foo",
-			expected: "foo",
-		},
-		{
-			ruleLiteral: `name: "//b"
-			rule_class: "ts_library"
-			attribute: <
-				type: 4
-				name: "module_name"
-				string_value: "foo"
-			>`,
-			imported: "bar",
-			expected: "bar",
-		},
-		{
-			ruleLiteral: `name: "//c"
-			rule_class: "ts_library"
-			attribute: <
-				type: 4
-				name: "module_name"
-				string_value: "foo"
-			>`,
-			imported: "foo/bar",
-			expected: "c/bar",
-		},
-		{
-			ruleLiteral: `name: "//actual/loc:target"
-			rule_class: "ts_library"
-			attribute: <
-				type: 4
-				name: "module_name"
-				string_value: "foo/bar"
-			>
-			attribute: <
-			type: 4
-			name: "module_root"
-			string_value: "mod/root"
-			>`,
-			imported: "foo/bar/baz/bam",
-			expected: "actual/loc/mod/root/baz/bam",
-		},
-	}
-	for _, test := range tests {
-		rule, err := parseRuleLiteral(test.ruleLiteral)
-		if err != nil {
-			t.Errorf("isRuleAnAlias(%q): failed to parse literal: %s", test.ruleLiteral, err)
-			continue
-		}
-		if actual := resolveAgainstModuleRoot(rule, test.imported); actual != test.expected {
-			t.Errorf("resolveAgainstModuleRoot(%q): got %q, want %q", rule.GetName(), actual, test.expected)
-		}
-	}
-}
-
-func TestParsePackageName(t *testing.T) {
-	tests := []struct {
-		input, scope, pkg string
-	}{
-		{"foo/bar", "foo", "bar"},
-		{"foo/bar/baz", "foo", "bar"},
-		{"foo", "foo", ""},
-		{"", "", ""},
-	}
-	for _, test := range tests {
-		if scope, pkg := parsePackageName(test.input); scope != test.scope || pkg != test.pkg {
-			t.Errorf("moduleName(%q): got %q, %q, want %q, %q", test.input, scope, pkg, test.scope, test.pkg)
-		}
-	}
-}
-
-func parseRuleLiteral(literal string) (*appb.Rule, error) {
-	var rule appb.Rule
-	if err := proto.UnmarshalText(literal, &rule); err != nil {
-		return nil, err
-	}
-	return &rule, nil
-}
diff --git a/ts_auto_deps/main.go b/ts_auto_deps/main.go
deleted file mode 100644
index 553afbc..0000000
--- a/ts_auto_deps/main.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package main
-
-import (
-	"flag"
-	"fmt"
-	"os"
-
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/updater"
-)
-
-var (
-	isRoot = flag.Bool("root", false, "the given path is the root of a TypeScript project "+
-		"(generates ts_config and ts_development_sources targets).")
-	recursive = flag.Bool("recursive", false, "recursively update all packages under the given root.")
-	files     = flag.Bool("files", false, "treats arguments as file names. Filters .ts files, then runs on their dirnames.")
-)
-
-func usage() {
-	fmt.Fprintf(os.Stderr, `ts_auto_deps: generate BUILD rules for TypeScript sources.
-
-usage: %s [flags] [path...]
-
-ts_auto_deps generates and updates BUILD rules for each of the given package paths.
-Paths are expected to reside underneath the workspace root. If none is given,
-ts_auto_deps runs on the current working directory.
-
-For each of the given package paths, ts_auto_deps finds all TypeScript sources in the
-package and adds sources that are not currently built to the appropriate
-BUILD rule (ts_library or ts_declaration).
-
-If there is no matching BUILD rule, or no BUILD file, ts_auto_deps will create either.
-
-ts_auto_deps also updates BUILD rule dependencies ('deps') based on the source imports.
-
-Flags:
-`, os.Args[0])
-	flag.PrintDefaults()
-}
-
-func main() {
-	flag.Usage = usage
-	flag.Parse()
-
-	paths, err := updater.Paths(*isRoot, *files, *recursive)
-	if err != nil {
-		platform.Error(err)
-	}
-
-	host := updater.New(false, false, updater.QueryBasedBazelAnalyze, updater.LocalUpdateFile)
-	if err := updater.Execute(host, paths, *isRoot, *recursive); err != nil {
-		platform.Error(err)
-	}
-}
diff --git a/ts_auto_deps/platform/BUILD.bazel b/ts_auto_deps/platform/BUILD.bazel
deleted file mode 100644
index 9e351ab..0000000
--- a/ts_auto_deps/platform/BUILD.bazel
+++ /dev/null
@@ -1,11 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
-    name = "go_default_library",
-    srcs = [
-        "file.go",
-        "log.go",
-    ],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/platform",
-    visibility = ["//visibility:public"],
-)
diff --git a/ts_auto_deps/platform/file.go b/ts_auto_deps/platform/file.go
deleted file mode 100644
index 7df93d0..0000000
--- a/ts_auto_deps/platform/file.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package platform
-
-import (
-	"context"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"strings"
-)
-
-const (
-	filePerms = 0666
-)
-
-var pathReplacer = strings.NewReplacer("\\", "/")
-
-// ReadFile reads the contents of name.
-func ReadFile(ctx context.Context, name string) ([]byte, error) {
-	return ioutil.ReadFile(name)
-}
-
-// ReadBytesFromFile reads bytes into the buffer provided, stopping when the
-// buffer is full.
-func ReadBytesFromFile(ctx context.Context, name string, buffer []byte) (int, error) {
-	f, err := os.Open(name)
-	if err != nil {
-		return 0, err
-	}
-	defer f.Close()
-
-	n, err := f.Read(buffer)
-	return n, err
-}
-
-// WriteFile writes data to filename.
-func WriteFile(ctx context.Context, filename string, data []byte) error {
-	return ioutil.WriteFile(filename, data, filePerms)
-}
-
-// Stat reads the file system information of name.
-func Stat(ctx context.Context, name string) (interface{}, error) {
-	return os.Stat(name)
-}
-
-// Glob returns all paths matching pattern.
-func Glob(ctx context.Context, pattern string) ([]string, error) {
-	return filepath.Glob(pattern)
-}
-
-// Normalize converts Windows path separators into POSIX
-func Normalize(path string) string {
-	return pathReplacer.Replace(path)
-}
diff --git a/ts_auto_deps/platform/log.go b/ts_auto_deps/platform/log.go
deleted file mode 100644
index 4fb889e..0000000
--- a/ts_auto_deps/platform/log.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package platform
-
-import (
-	"fmt"
-	"log"
-	"os"
-)
-
-// Infof prints a formatted message to stdout.
-func Infof(format string, args ...interface{}) {
-	fmt.Printf(format+"\n", args...)
-}
-
-// Error prints a series of args to stderr.
-func Error(args ...interface{}) {
-	fmt.Fprintln(os.Stderr, args...)
-}
-
-// Fatalf prints a formatted message to stderr. Panics after printing.
-func Fatalf(format string, v ...interface{}) {
-	log.Fatalf(format, v...)
-}
diff --git a/ts_auto_deps/platform/walk.go b/ts_auto_deps/platform/walk.go
deleted file mode 100644
index 05dd366..0000000
--- a/ts_auto_deps/platform/walk.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package platform
-
-import (
-	"os"
-	"path/filepath"
-)
-
-func Walk(root string, walkFn func(path string, typ os.FileMode) error) error {
-	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return err
-		}
-		return walkFn(path, info.Mode())
-	})
-}
diff --git a/ts_auto_deps/proto/BUILD.bazel b/ts_auto_deps/proto/BUILD.bazel
deleted file mode 100644
index e7e793a..0000000
--- a/ts_auto_deps/proto/BUILD.bazel
+++ /dev/null
@@ -1,22 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
-
-proto_library(
-    name = "bazel_analyze_proto",
-    srcs = ["analyze_result.proto"],
-    visibility = ["//visibility:public"],
-)
-
-go_proto_library(
-    name = "bazel_analyze_go_proto",
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto",
-    proto = ":bazel_analyze_proto",
-    visibility = ["//visibility:public"],
-)
-
-go_library(
-    name = "go_default_library",
-    embed = [":bazel_analyze_go_proto"],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto",
-    visibility = ["//visibility:public"],
-)
diff --git a/ts_auto_deps/proto/analyze_result.proto b/ts_auto_deps/proto/analyze_result.proto
deleted file mode 100644
index 49ee500..0000000
--- a/ts_auto_deps/proto/analyze_result.proto
+++ /dev/null
@@ -1,98 +0,0 @@
-syntax = "proto2";
-
-package bazel_analyze;
-
-// A DependencyGroup represents a list of alternatives for satisfying
-// a missing dependency.
-message DependencyGroup {
-  // Represents the visibility status of this dependency group. All the
-  // dependencies have the same visibility status indicated by the visibility
-  // field. Producers of this message (i.e. checkdeps) will ensure that
-  // the invariant is true.
-  enum Visibility {
-    // Visibility was not considered. (Default)
-    UNKNOWN = 0;
-    // All the alternatives are visible
-    ALL_VISIBLE = 1;
-    // All the alternatives are invisible
-    ALL_INVISIBLE = 2;
-  }
-
-  repeated string dependency = 1;
-  optional Visibility visibility = 2 [default = UNKNOWN];
-  // The set of import paths for which any of these dependencies can provide.
-  // It is legal for there to be multiple entries there (in practice it is
-  // not very common). This happens if the dependencies required by one
-  // import_path is a subset of the other. In that case, the smaller set of
-  // dependencies is populated in dependency field, and both import_path's are
-  // listed here.
-  repeated string import_path = 3;
-}
-
-// Represents information about arbitrary non-deps attributes.
-message AttributeReport {
-  // Name of the attribute (e.g. "runtime_deps").
-  optional string attribute = 1;
-  // Attribute value that is required but missing.
-  repeated string missing_value = 2;
-  // Attribute value that is declared but not needed.
-  repeated string unnecessary_value = 3;
-}
-
-// The result of checking a single build rule (called X in comments
-// below) for missing or unnecessary dependencies.  Produced by
-// java/com/google/devtools/build/checkbuilddeps (which for external
-// users means it's produced by bazel analyze).
-message DependencyReport {
-  required string rule = 1;  // Name of rule X, in canonical google3 format.
-
-  // Names of targets that are, or should be, declared as dependencies
-  // by rule X.  Some need to be declared and some don't; in some
-  // cases it is impossible to tell by static analysis.  Each is the
-  // full canonical name of the target, i.e. //x/y:z, or the shorthand
-  // form if the target name equals the package name, i.e. //x/y
-  // (shorthand for //x/y:y).
-
-  // Declared and needed. Removing these dependencies should break the build.
-  repeated string necessary_dependency = 2;
-
-  // Declared but not needed. Removing these dependencies should not break
-  // the build.
-  repeated string unnecessary_dependency = 3;
-
-  // Can't tell. These may be dependencies where no corresponding imports
-  // were found, but alwayslink=1.
-  repeated string ambiguous_dependency = 4;
-
-  // Needed but not declared. If there are imports which can be satisfied
-  // by more than one dependency declared in a best-matching package, list
-  // all of them. If this list is not empty, we expect the build to break.
-  repeated DependencyGroup missing_dependency_group = 8;
-
-  // Files/classes that a source file imports, but for which no
-  // appropriate dependency could be found. We expect the build to break
-  // if this list is not empty.
-  // NOTE: If there are unreseolved imports, it may indicate that
-  // analysis failed to connect a declared dependency with a
-  // corresponding import statement, and so you may want to have less
-  // faith in the unnecessary_dependency field (though, in general,
-  // rules in unnecessary_dependency are still PROBABLY unnecessary).
-  repeated string unresolved_import = 7;
-
-  // Source files that are inputs to the rule but cannot be found.
-  // Values are absolute labels, e.g. '//foo:bar/baz.c'.
-  repeated string missing_source_file = 13;
-
-  // General-purpose feedback messages from the dependency checker
-  // (errors, warnings, any kind of info).
-  repeated string feedback = 6;
-
-  // Indicates whether the dependency analysis completed without errors.
-  optional bool successful = 10 [default = true];
-}
-
-// Aggregate DependencyReports for multiple analysis
-// targets - used to support bazel analyze --analysis_output=proto
-message AnalyzeResult {
-  repeated DependencyReport dependency_report = 1;
-}
diff --git a/ts_auto_deps/updater/BUILD.bazel b/ts_auto_deps/updater/BUILD.bazel
deleted file mode 100644
index 53e319c..0000000
--- a/ts_auto_deps/updater/BUILD.bazel
+++ /dev/null
@@ -1,29 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-
-go_library(
-    name = "go_default_library",
-    srcs = ["updater.go"],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/updater",
-    visibility = ["//visibility:public"],
-    deps = [
-        "//ts_auto_deps/analyze:go_default_library",
-        "//ts_auto_deps/platform:go_default_library",
-        "//ts_auto_deps/proto:go_default_library",
-        "//ts_auto_deps/workspace:go_default_library",
-        "@com_github_bazelbuild_buildtools//build:go_default_library",
-        "@com_github_bazelbuild_buildtools//edit:go_default_library",
-        "@com_github_golang_protobuf//proto:go_default_library",
-        "@com_github_mattn_go_isatty//:go_default_library",
-    ],
-)
-
-go_test(
-    name = "go_default_test",
-    srcs = ["updater_test.go"],
-    embed = [":go_default_library"],
-    deps = [
-        "//ts_auto_deps/proto:go_default_library",
-        "@com_github_bazelbuild_buildtools//build:go_default_library",
-        "@com_github_golang_protobuf//proto:go_default_library",
-    ],
-)
diff --git a/ts_auto_deps/updater/test_register.go b/ts_auto_deps/updater/test_register.go
deleted file mode 100644
index 0f51e63..0000000
--- a/ts_auto_deps/updater/test_register.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package updater
-
-import (
-	"context"
-	"fmt"
-	"path/filepath"
-
-	"github.com/bazelbuild/buildtools/build"
-	"github.com/bazelbuild/buildtools/edit"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-)
-
-// isAllTestLibrary identifies testonly ts_libraries named "all_tests".  Taze
-// will register tests with these rules instead of
-// ts_config/ts_development_sources rules to allow users to set up their builds
-// differently.
-func isAllTestLibrary(bld *build.File, r *build.Rule) bool {
-	if !ruleMatches(bld, r, "ts_library", ruleTypeTest) {
-		return false
-	}
-
-	if r.Name() != "all_tests" {
-		return false
-	}
-
-	return true
-}
-
-func getAllTestLibraries(bld *build.File) []*build.Rule {
-	var allTestRules []*build.Rule
-	for _, r := range buildRules(bld, "ts_library") {
-		if isAllTestLibrary(bld, r) {
-			allTestRules = append(allTestRules, r)
-		}
-	}
-	return allTestRules
-}
-
-// RegisterTestRules registers ts_library test targets with the project's
-// ts_config and ts_development_sources rules.  It may also register the tests
-// with a testonly ts_library named "all_tests", which allows users to set up
-// their own BUILD layout.  It's separated from UpdateBUILD since it's
-// non-local, multiple packages may all need to make writes to the same
-// ts_config.  It returns a set of the paths for the packages that were updated.
-func (upd *Updater) RegisterTestRules(ctx context.Context, paths ...string) (bool, map[string]bool, error) {
-	reg := &buildRegistry{make(map[string]*build.File), make(map[*build.File]bool)}
-	var g3root string
-	updatedAncestorPackages := make(map[string]bool)
-	for _, path := range paths {
-		// declare variables manually so that g3root doesn't get overwritten by a :=
-		// declaration
-		var err error
-		var buildPath string
-		g3root, buildPath, _, err = getBUILDPath(ctx, path)
-		if err != nil {
-			return false, nil, err
-		}
-		bld, err := reg.readBUILD(ctx, g3root, buildPath)
-		if err != nil {
-			return false, nil, err
-		}
-		for _, tr := range getRules(bld, "ts_library", ruleTypeTest) {
-			// don't register all_test libraries themselves
-			if isAllTestLibrary(bld, tr) {
-				continue
-			}
-			platform.Infof("Registering test rule in closest ts_config & ts_development_sources")
-			target := AbsoluteBazelTarget(bld, tr.Name())
-			ancestorBuild, err := reg.registerTestRule(ctx, bld, tsConfig, g3root, target)
-			if err != nil {
-				return false, nil, err
-			}
-			if ancestorBuild != "" {
-				updatedAncestorPackages[ancestorBuild] = true
-			}
-			// NodeJS rules should not be added to ts_development_sources automatically, because
-			// they typically do not run in the browser.
-			if tr.AttrString("runtime") != "nodejs" {
-				ancestorBuild, err := reg.registerTestRule(ctx, bld, tsDevSrcs, g3root, target)
-				if err != nil {
-					return false, nil, err
-				}
-				if ancestorBuild != "" {
-					updatedAncestorPackages[ancestorBuild] = true
-				}
-			}
-		}
-	}
-
-	updated := false
-	for b := range reg.filesToUpdate {
-		fmt.Printf("Registered test(s) in %s\n", b.Path)
-		fileChanged, err := upd.maybeWriteBUILD(ctx, filepath.Join(g3root, b.Path), b)
-		if err != nil {
-			return false, nil, err
-		}
-		updated = updated || fileChanged
-	}
-
-	return updated, updatedAncestorPackages, nil
-}
-
-// buildRegistry buffers reads and writes done while registering ts_libraries
-// with ts_config and ts_development_sources rules, so that registers from
-// multiple packages all get applied at once.
-type buildRegistry struct {
-	bldFiles      map[string]*build.File
-	filesToUpdate map[*build.File]bool
-}
-
-func (reg *buildRegistry) readBUILD(ctx context.Context, workspaceRoot, buildFilePath string) (*build.File, error) {
-	normalizedG3Path, err := getWorkspaceRelativePath(workspaceRoot, buildFilePath)
-	if err != nil {
-		return nil, err
-	}
-
-	if bld, ok := reg.bldFiles[normalizedG3Path]; ok {
-		return bld, nil
-	}
-
-	bld, err := readBUILD(ctx, buildFilePath, normalizedG3Path)
-	if err != nil {
-		return nil, err
-	}
-	if bld == nil {
-		// The BUILD file didn't exist, so create a new, empty one.
-		bld = &build.File{Path: normalizedG3Path, Type: build.TypeBuild}
-	}
-
-	reg.bldFiles[normalizedG3Path] = bld
-
-	return bld, nil
-}
-
-func (reg *buildRegistry) registerForPossibleUpdate(bld *build.File) {
-	reg.filesToUpdate[bld] = true
-}
-
-type registerTarget int
-
-const (
-	tsConfig registerTarget = iota
-	tsDevSrcs
-)
-
-func (rt registerTarget) kind() string {
-	if rt == tsConfig {
-		return "ts_config"
-	}
-
-	return "ts_development_sources"
-}
-
-func (rt registerTarget) ruleType() ruleType {
-	if rt == tsConfig {
-		return ruleTypeAny
-	}
-
-	return ruleTypeTest
-}
-
-// registerTestRule searches ancestor packages for a rule matching the register
-// target and adds the given target to it. If an all_tests library is found, the
-// rule is registered with it, instead of specified register target. Prints a
-// warning if no rule is found, but only returns an error if adding the
-// dependency fails.
-func (reg *buildRegistry) registerTestRule(ctx context.Context, bld *build.File, rt registerTarget, g3root, target string) (string, error) {
-	if buildHasDisableTaze(bld) {
-		return "", nil
-	}
-
-	var ruleToRegister *build.Rule
-	for _, r := range bld.Rules("") {
-		if isAllTestLibrary(bld, r) {
-			if hasDependency(bld, r, target) {
-				return "", nil
-			}
-
-			// an all_tests library takes presidence over a registerTarget, and there
-			// can only be one, since there can only be one rule with a given name, so
-			// can just break after finding
-			ruleToRegister = r
-			break
-		}
-		if ruleMatches(bld, r, rt.kind(), rt.ruleType()) {
-			if hasDependency(bld, r, target) {
-				return "", nil
-			}
-
-			// keep overwriting ruleToRegister so the last match in the BUILD gets
-			// used
-			ruleToRegister = r
-		}
-	}
-
-	if ruleToRegister != nil {
-		addDep(bld, ruleToRegister, target)
-		reg.registerForPossibleUpdate(bld)
-		return filepath.Dir(bld.Path), nil
-	}
-
-	parentDir := filepath.Dir(filepath.Dir(bld.Path))
-	for parentDir != "." && parentDir != "/" {
-		buildFile := filepath.Join(g3root, parentDir, "BUILD")
-		if _, err := platform.Stat(ctx, buildFile); err == nil {
-			parent, err := reg.readBUILD(ctx, g3root, buildFile)
-			if err != nil {
-				return "", err
-			}
-			return reg.registerTestRule(ctx, parent, rt, g3root, target)
-		}
-		parentDir = filepath.Dir(parentDir)
-	}
-	fmt.Printf("WARNING: no %s rule in parent packages of %s to register with.\n",
-		rt.kind(), target)
-	return "", nil
-}
-
-var wellKnownBuildRules = []struct {
-	name     string
-	attrName string
-}{
-	{
-		name:     "karma_polymer_test",
-		attrName: "test_ts_deps",
-	},
-	{
-		name:     "wct_closure_test_suite",
-		attrName: "js_deps",
-	},
-	{
-		name:     "jasmine_node_test",
-		attrName: "deps",
-	},
-	{
-		name:     "karma_web_test_suite",
-		attrName: "deps",
-	},
-	{
-		name:     "boq_jswire_test_library",
-		attrName: "deps",
-	},
-}
-
-// isRegisteredWithAlternateTestRule returns true if the rule is already
-// registered with a well known test rule, such as karma_polymer_test,
-// wct_closure_test_suite or jasmine_node_test.
-func isRegisteredWithAlternateTestRule(bld *build.File, r *build.Rule, dep string) bool {
-	pkg := filepath.Dir(bld.Path)
-	for _, wkbr := range wellKnownBuildRules {
-		if isKind(r, wkbr.name) {
-			testTsDeps := r.Attr(wkbr.attrName)
-			if edit.ListFind(testTsDeps, dep, pkg) != nil {
-				return true
-			}
-		}
-	}
-	return false
-}
diff --git a/ts_auto_deps/updater/updater.go b/ts_auto_deps/updater/updater.go
deleted file mode 100644
index f606e5b..0000000
--- a/ts_auto_deps/updater/updater.go
+++ /dev/null
@@ -1,1340 +0,0 @@
-// Package updater implements the main logic of the ts_auto_deps command. It reads BUILD files,
-// discovers TypeScript sources, uses `bazel analyze` to update import/dependency information,
-// and then modifies the BUILD file accordingly.
-package updater
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"io"
-	"os"
-	"path/filepath"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-
-	"flag"
-	"github.com/bazelbuild/buildtools/build"
-	"github.com/bazelbuild/buildtools/edit"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/analyze"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/platform"
-	"github.com/bazelbuild/rules_typescript/ts_auto_deps/workspace"
-	"github.com/golang/protobuf/proto"
-	"github.com/mattn/go-isatty"
-
-	arpb "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto"
-)
-
-var bazelErrorRE = regexp.MustCompile(`ERROR: ([^:]+):(\d+):\d+:`)
-
-// New creates a new updater from the given arguments. One updater can be used
-// to update many packages, repeatedly, but not concurrently.
-// bazelAnalyze and updateFile can be passed in to handle ts_auto_deps operation in
-// different environments and for fakes in tests.
-func New(removeUnusedDeclarations bool, updateComments bool, bazelAnalyze BazelAnalyzer, updateFile UpdateFile) *Updater {
-	return &Updater{removeUnusedDeclarations, updateComments, bazelAnalyze, updateFile}
-}
-
-// UpdateFile updates the contents of filePath. Implementations may postpone or batch actually writing the given file, i.e.
-// a subsequent read may return stale contents.
-type UpdateFile func(ctx context.Context, filePath string, contents string) error
-
-// LocalUpdateFile simply writes to the given file.
-func LocalUpdateFile(ctx context.Context, filePath string, contents string) error {
-	return platform.WriteFile(ctx, filePath, []byte(contents))
-}
-
-// BazelAnalyzer is a function that executes bazel analyze for the given
-// absolute build file path and bazel targets, and returns the raw analysis
-// result proto, or an error if the analyze call failed.
-// It's used to abstract over execution using rabbit vs local execution.
-// Returns the main output (serialized AnalysisResult proto), any error
-// messages, or an error.
-type BazelAnalyzer func(buildFilePath string, targets []string) ([]byte, []byte, error)
-
-// Updater encapsulates configuration for the ts_auto_deps process.
-type Updater struct {
-	removeUnusedDeclarations bool
-	updateComments           bool
-	bazelAnalyze             BazelAnalyzer
-	updateFile               UpdateFile
-}
-
-func attrTruthy(r *build.Rule, attr string) bool {
-	attrVal := r.AttrLiteral(attr)
-	return attrVal == "True" || attrVal == "1"
-}
-
-// Matches the warning TypeScriptRuleChecker prints for unused ts_declarations.
-// TODO(martinprobst): in the long term, this should become the default and TypeScriptRuleChecker should no longer special case ts_declaration.
-var unusedDeclarationRE = regexp.MustCompile(
-	`WARNING: [^:]+:\d+:(?:\d+:)? keeping possibly used ts_declaration '([^']+)'`)
-
-// GarbledBazelResponseError signals to callers that the proto returned by bazel
-// analyze was garbled, and couldn't be unmarshalled.
-// TODO(lucassloan): remove when b/112891536 is fixed
-// Build Rabbit rewrites paths produced by bazel, which garbles the error
-// messages from bazel analyze, since they're encoded in protobufs.
-type GarbledBazelResponseError struct {
-	Message string
-}
-
-func (g *GarbledBazelResponseError) Error() string {
-	return g.Message
-}
-
-// runBazelAnalyze executes the `bazel analyze` command and extracts reports.
-// It returns the dependency report with rule names referring to rules *before*
-// macro expansion, or an error. runBazelAnalyze uses the given `analyze`
-// function to actually run the `bazel analyze` operation, which allows
-// exchanging it for a different implementation in the ts_auto_deps presubmit service.
-func (upd *Updater) runBazelAnalyze(buildFilePath string, bld *build.File, rules []*build.Rule) ([]*arpb.DependencyReport, error) {
-	var targets []string
-	for _, r := range rules {
-		fullTarget := AbsoluteBazelTarget(bld, r.Name())
-		targets = append(targets, fullTarget)
-	}
-	out, stderr, err := upd.bazelAnalyze(buildFilePath, targets)
-	if err != nil {
-		return nil, err
-	}
-
-	var res arpb.AnalyzeResult
-	if err := proto.Unmarshal(out, &res); err != nil {
-		// TODO(lucassloan): remove when b/112891536 is fixed
-		// Build Rabbit rewrites paths produced by bazel, which garbles the error
-		// messages from bazel analyze, since they're encoded in protobufs.
-		return nil, &GarbledBazelResponseError{fmt.Sprintf("failed to unmarshal analysis result: %v\nin: %q", err, string(out))}
-	}
-	platform.Infof("analyze result %v", res)
-	reports := res.GetDependencyReport()
-	if len(targets) != len(reports) {
-		if len(stderr) > 0 {
-			// TODO(b/73321854): pretend second rule has a syntactical error, so bazel analyze produces no
-			// report for it, but also doesn't return an error code. Remove workaround once fixed.
-			return nil, fmt.Errorf("parsing reports failed (%d reports for %s):\n%s",
-				len(reports), targets, stderr)
-		}
-		return nil, fmt.Errorf("parsing reports failed (%d reports for %s) in output: %s",
-			len(reports), targets, out)
-	}
-	if upd.removeUnusedDeclarations {
-		for _, report := range reports {
-			for _, fb := range report.GetFeedback() {
-				m := unusedDeclarationRE.FindStringSubmatch(fb)
-				if m == nil {
-					continue
-				}
-				target := m[1]
-				platform.Infof("Removing (possibly) unused ts_declaration dependency %q", target)
-				// TODO(martinprobst): this warning is to educate users after changing removeUnusedDeclarations to true by default.
-				// Once existing code is fixed, this constitutes normal operation, and the logging below should be dropped.
-				fmt.Fprintf(os.Stderr, "WARNING: removing apparently unused ts_declaration() dependency from %q.\n", report.GetRule())
-
-				report.UnnecessaryDependency = append(report.UnnecessaryDependency, target)
-			}
-		}
-	}
-	return reports, nil
-}
-
-func spin(prefix string) chan<- struct{} {
-	done := make(chan struct{})
-	// Check for cygwin, important for Windows compatibility
-	if !isatty.IsTerminal(os.Stderr.Fd()) || !isatty.IsCygwinTerminal(os.Stdout.Fd()) {
-		return done
-	}
-	go func() {
-		// Wait a bit before starting to print to avoid flashing a spinner unnecessarily.
-		time.Sleep(100 * time.Millisecond)
-		ticker := time.NewTicker(100 * time.Millisecond)
-		defer ticker.Stop()
-		i := 0
-		str := []rune(`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`)
-		for {
-			select {
-			case <-done:
-				fmt.Fprint(os.Stderr, "\r")
-				for i := 0; i < len(prefix)+2; i++ {
-					fmt.Fprint(os.Stderr, " ")
-				}
-				fmt.Fprint(os.Stderr, "\r")
-				return
-			case <-ticker.C:
-				fmt.Fprintf(os.Stderr, "\r%s %s", prefix, string(str[i]))
-				i = (i + 1) % len(str)
-			}
-		}
-	}()
-	return done
-}
-
-// readBUILD loads the BUILD file, if present, or returns a nil pointer, if not.
-// buildFilePath is relative to CWD, and workspaceRelativePath is relative to
-// the workspace root (the directory containing the WORKSPACE file).
-func readBUILD(ctx context.Context, buildFilePath, workspaceRelativePath string) (*build.File, error) {
-	data, err := platform.ReadFile(ctx, buildFilePath)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return nil, nil
-		}
-		return nil, err
-	}
-	bld, err := build.ParseBuild(workspaceRelativePath, data)
-	if err != nil {
-		if parseErr, ok := err.(build.ParseError); ok {
-			return nil, &AnalysisFailedError{
-				[]AnalysisFailureCause{
-					AnalysisFailureCause{
-						Message: parseErr.Error(),
-						Path:    parseErr.Filename,
-						Line:    parseErr.Pos.Line,
-					},
-				},
-			}
-
-		}
-
-		// wasn't an error we know how to parse
-		return nil, err
-	}
-	return bld, nil
-}
-
-type srcSet map[string]bool
-
-type globResult struct {
-	srcs srcSet
-	err  error
-}
-
-// globSources finds sources in path with any of the given extensions.
-// It also filters out temporary files, dangling symlinks, and symlinks into bazel-bin specifically.
-// It returns file names relative to path.
-func globSources(ctx context.Context, path string, extensions []string) (srcSet, error) {
-	var allSourcePaths []string
-	for _, extension := range extensions {
-		pattern := "*." + extension
-		matched, err := platform.Glob(ctx, filepath.Join(path, pattern))
-		if err != nil {
-			return nil, fmt.Errorf("glob(%s): %s", pattern, err)
-		}
-		allSourcePaths = append(allSourcePaths, matched...)
-	}
-	srcs := make(srcSet)
-	for _, p := range allSourcePaths {
-		fileName := filepath.Base(p)
-		if isTempFile(fileName) {
-			continue // Ignore editor swap/backup files.
-		}
-		// Try platform.Stat as a fallback, for Google file systems.
-		_, err := platform.Stat(ctx, p)
-		if os.IsNotExist(err) {
-			platform.Infof("platform.Glob returned non-existent file (dangling symlink?). Ignoring %q.", p)
-			continue
-		}
-		if err != nil {
-			return nil, fmt.Errorf("cannot stat platform.Glob result %q: %v", p, err)
-		}
-		isMpeg, err := IsMpegTS(ctx, p)
-		if err != nil {
-			return nil, err
-		}
-		if isMpeg {
-			continue
-		}
-		p, err := filepath.Rel(path, p)
-		if err != nil {
-			return nil, fmt.Errorf("filepath.Rel(%s, %s): %v", path, p, err)
-		}
-		srcs[p] = true
-	}
-	return srcs, nil
-}
-
-// IsMpegTS checks if a ".ts" file is an MPEG transport stream.  Taze shouldn't
-// treat them as TypeScript files.
-func IsMpegTS(ctx context.Context, path string) (bool, error) {
-	var content [200]byte
-	n, err := platform.ReadBytesFromFile(ctx, path, content[:])
-	if err != nil && err != io.EOF {
-		return false, err
-	}
-
-	// MPEG TS' frame format starts with 0x47 every 189 bytes - detect that and return.
-	isMpeg := n > 188 && content[0] == 0x47 && content[188] == 0x47
-	return isMpeg, nil
-}
-
-func isTempFile(fileName string) bool {
-	return strings.HasPrefix(fileName, ".") || strings.HasSuffix(fileName, ".swp") ||
-		strings.HasSuffix(fileName, "~")
-}
-
-// updateSources adds any srcs that are not in some rule to the last ts_* rule
-// in the package, or create a new rule for them.
-func updateSources(bld *build.File, srcs srcSet) {
-	removeSourcesUsed(bld, "ts_library", "srcs", srcs)
-	removeSourcesUsed(bld, "ts_declaration", "srcs", srcs)
-
-	if len(srcs) == 0 {
-		return
-	}
-
-	// Sort the remaining sources for reproducibility (sadly Go has no LinkedHashSet)
-	var srcSlice []string
-	for s := range srcs {
-		srcSlice = append(srcSlice, s)
-	}
-	sort.Strings(srcSlice)
-
-	pkgName := filepath.Base(filepath.Dir(bld.Path))
-	platform.Infof("Adding new sources to targets in %q: %q", pkgName, srcSlice)
-	for _, s := range srcSlice {
-		var r *build.Rule
-		ruleName := pkgName
-		if strings.HasSuffix(s, ".d.ts") {
-			r = getOrCreateRule(bld, ruleName+"_dts", "ts_declaration", ruleTypeRegular)
-		} else {
-			rt := determineRuleType(bld.Path, s)
-			r = getOrCreateRule(bld, ruleName, "ts_library", rt)
-		}
-		addToSrcsClobbering(bld, r, s)
-	}
-}
-
-// Adds the given value to the srcs attribute on the build rule. Clobbers any
-// existing values for srcs that are not a list.
-func addToSrcsClobbering(bld *build.File, r *build.Rule, s string) {
-	value := r.Attr("srcs")
-	switch value.(type) {
-	case nil, *build.ListExpr:
-		// expected - a list of files (labels) or absent.
-	default:
-		// Remove any glob calls, variables, etc. ts_auto_deps uses explicit source lists.
-		fmt.Fprintf(os.Stderr, "WARNING: clobbering non-list srcs attribute on %s\n",
-			AbsoluteBazelTarget(bld, r.Name()))
-		r.DelAttr("srcs")
-	}
-	val := &build.StringExpr{Value: s}
-	edit.AddValueToListAttribute(r, "srcs", "", val, nil)
-}
-
-var testingRegexp = regexp.MustCompile(`\btesting\b`)
-
-func determineRuleType(path, s string) ruleType {
-	if strings.HasSuffix(s, "_test.ts") || strings.HasSuffix(s, "_test.tsx") {
-		return ruleTypeTest
-	}
-
-	return ruleTypeRegular
-}
-
-// AnalysisFailedError is returned by ts_auto_deps when the underlying analyze operation
-// fails, e.g. because the BUILD files have syntactical errors.
-type AnalysisFailedError struct {
-	Causes []AnalysisFailureCause
-}
-
-// AnalysisFailureCause gives (one of) the reasons analysis failed, along with
-// the path and line that caused the failure (if available).
-type AnalysisFailureCause struct {
-	Message string
-	// workspace path of the file on which analysis failed ie foo/bar/baz.ts, not
-	// starting with google3/
-	Path string
-	// 1-based line on which analysis failed
-	Line int
-}
-
-func (a *AnalysisFailedError) Error() string {
-	var messages []string
-	for _, c := range a.Causes {
-		messages = append(messages, c.Message)
-	}
-	return strings.Join(messages, "\n")
-}
-
-// updateDeps adds missing dependencies and removes unnecessary dependencies
-// for the targets in the given DependencyReports to the build rules in bld.
-func updateDeps(bld *build.File, reports []*arpb.DependencyReport) error {
-	// First, check *all* reports on whether they were successful, so that users
-	// get the complete set of errors at once.
-	var errors []AnalysisFailureCause
-	for _, report := range reports {
-		if !report.GetSuccessful() {
-			for _, fb := range report.GetFeedback() {
-				msg := fmt.Sprintf("dependency analysis failed for %s:\n%s",
-					report.GetRule(), fb)
-
-				m := bazelErrorRE.FindStringSubmatch(fb)
-				if m == nil {
-					// error message didn't contain file and line number, so just use the
-					// path of the BUILD file that was analyzed
-					errors = append(errors, AnalysisFailureCause{Message: msg, Path: bld.Path})
-					continue
-				}
-
-				file := m[1]
-				line, err := strconv.Atoi(m[2])
-				if err != nil {
-					return err
-				}
-
-				errors = append(errors, AnalysisFailureCause{msg, file, line})
-			}
-		}
-	}
-	if len(errors) > 0 {
-		return &AnalysisFailedError{errors}
-	}
-
-	pkg := filepath.Dir(bld.Path)
-	for _, report := range reports {
-		platform.Infof("Applying report: %s", report.String())
-		fullTarget := report.GetRule()
-		targetName := fullTarget[strings.LastIndex(fullTarget, ":")+1:]
-		r := edit.FindRuleByName(bld, targetName)
-		if r == nil {
-			return fmt.Errorf("could not find rule from report %v", targetName)
-		}
-		for _, md := range report.MissingDependencyGroup {
-			for _, d := range md.Dependency {
-				d = AbsoluteBazelTarget(bld, d)
-				if d == fullTarget {
-					return &AnalysisFailedError{
-						[]AnalysisFailureCause{
-							AnalysisFailureCause{
-								Message: fmt.Sprintf("target %s depends on itself. "+
-									"Maybe you have an incorrect `// from %s` comment, or need to split application "+
-									"entry point (main.ts) and ng_module() rule?", d, d),
-								Path: bld.Path,
-							},
-						},
-					}
-				}
-				platform.Infof("Adding dependency on %s to %s\n", d, fullTarget)
-				addDep(bld, r, d)
-			}
-		}
-		hadUnresolved := len(report.UnresolvedImport) > 0
-		if hadUnresolved {
-			return &AnalysisFailedError{
-				[]AnalysisFailureCause{
-					AnalysisFailureCause{
-						Message: fmt.Sprintf("ERROR in %s: unresolved imports %s.\nMaybe you are missing a "+
-							"'// from ...'' comment, or the target BUILD files are incorrect?\n%s\n",
-							fullTarget, report.UnresolvedImport, strings.Join(report.GetFeedback(), "\n")),
-						Path: bld.Path,
-					},
-				},
-			}
-		}
-		for _, d := range report.UnnecessaryDependency {
-			platform.Infof("Removing dependency on %s from %s\n", d, fullTarget)
-			edit.ListAttributeDelete(r, "deps", d, pkg)
-		}
-		for _, s := range report.MissingSourceFile {
-			platform.Infof("Removing missing source %s from %s\n", s, fullTarget)
-			edit.ListAttributeDelete(r, "srcs", s, pkg)
-		}
-	}
-	return nil
-}
-
-// maybeWriteBUILD checks if the given file needs updating, i.e. whether the
-// canonical serialized form of bld has changed from the file contents on disk.
-// If so, writes the file and returns true, returns false otherwise.
-func (upd *Updater) maybeWriteBUILD(ctx context.Context, path string, bld *build.File) (bool, error) {
-	ri := &build.RewriteInfo{}
-	build.Rewrite(bld, ri)
-	platform.Infof("Formatted %s: %s\n", path, ri)
-	newContent := build.Format(bld)
-	oldContent, err := platform.ReadFile(ctx, path)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return false, err
-		} else if len(newContent) == 0 {
-			// The BUILD file does not exist, and the newly created file has no content.
-			// Treat this as equivalent, and do not create a new BUILD file.
-			return false, nil
-		}
-		// Fall through to write a new file.
-	} else if bytes.Equal(oldContent, newContent) {
-		// Compare contents, only update if changed.
-		return false, nil
-	}
-	if err := upd.updateFile(ctx, path, string(newContent)); err != nil {
-		return false, fmt.Errorf("failed to update %q: %v", path, err)
-	}
-	return true, nil
-}
-
-// getWorkspaceRelativePath takes a buildFilePath that's relative to the working
-// directory, and returns a path to the BUILD file that's relative to the
-// workspaceRoot (the absolute path of the directory containing the WORKSPACE
-// file).
-func getWorkspaceRelativePath(workspaceRoot, buildFilePath string) (string, error) {
-	absPath, err := filepath.Abs(buildFilePath)
-	if err != nil {
-		return "", err
-	}
-	workspaceRelativePath, err := filepath.Rel(workspaceRoot, absPath)
-	if err != nil {
-		return "", err
-	}
-	platform.Normalize(workspaceRelativePath)
-
-	return workspaceRelativePath, nil
-}
-
-// getBUILDPath takes in a package or BUILD file path, and returns the path of
-// the workspace root (the absolute path of the directory containing the
-// WORKSPACE file), the BUILD file path relative to the working directory, and
-// the BUILD file path relative to the workspace root.
-func getBUILDPath(ctx context.Context, path string) (string, string, string, error) {
-	path = strings.TrimSuffix(path, "/BUILD") // Support both package paths and BUILD files
-	if _, err := platform.Stat(ctx, path); os.IsNotExist(err) {
-		return "", "", "", err
-	}
-	buildFilePath := filepath.Join(path, "BUILD")
-	workspaceRoot, err := workspace.Root(buildFilePath)
-	if err != nil {
-		return "", "", "", err
-	}
-
-	workspaceRelativePath, err := getWorkspaceRelativePath(workspaceRoot, buildFilePath)
-	if err != nil {
-		return "", "", "", err
-	}
-
-	return workspaceRoot, buildFilePath, workspaceRelativePath, nil
-}
-
-// isTazeDisabledInPackage checks the BUILD file, or if the BUILD doesn't exist,
-// the nearest ancestor BUILD file for a disable_ts_auto_deps() rule.
-func isTazeDisabledInPackage(ctx context.Context, g3root, buildFilePath, workspaceRelativePath string, bld *build.File) (bool, error) {
-	if bld == nil {
-		// Make sure ts_auto_deps hasn't been disabled in the next closest ancestor package.
-		ancestor, err := FindBUILDFile(ctx, make(map[string]*build.File), g3root, filepath.Dir(workspaceRelativePath))
-		if _, ok := err.(*noAncestorBUILDError); ok {
-			platform.Infof("Could not find any ancestor BUILD for %q, continuing with a new BUILD file",
-				buildFilePath)
-			return false, nil
-		} else if err != nil {
-			return false, err
-		} else if buildHasDisableTaze(ancestor) {
-			fmt.Printf("ts_auto_deps disabled below %q\n", ancestor.Path)
-			return true, nil
-		} else {
-			platform.Infof("BUILD file missing and ts_auto_deps is enabled below %q. Creating new BUILD file.",
-				ancestor.Path)
-			return false, nil
-		}
-	}
-
-	if buildHasDisableTaze(bld) {
-		fmt.Printf("ts_auto_deps disabled on %q\n", buildFilePath)
-		return true, nil
-	}
-
-	return false, nil
-}
-
-// SubdirectorySourcesError is returned when ts_auto_deps detects a BUILD file
-// that references sources in another directory, either in the directory
-// being ts_auto_depsd, or in a super directory.
-type SubdirectorySourcesError struct{}
-
-func (a *SubdirectorySourcesError) Error() string {
-	return "ts_auto_deps doesn't handle referencing sources in another directory " +
-		"- to use ts_auto_deps, migrate to having a BUILD file in every directory. " +
-		"For more details, see go/ts_auto_deps#subdirectory-sources"
-}
-
-// hasSubdirectorySources checks if the BUILD file has ts_libraries that contain
-// source files from subdirectories of the directory with the BUILD. ie foo/BUILD
-// has a src foo/bar/baz.ts, in the subdirectory foo/bar.
-func hasSubdirectorySources(bld *build.File) bool {
-	for _, rule := range buildRules(bld, "ts_library") {
-		srcs := rule.AttrStrings("srcs")
-		if srcs != nil {
-			for _, s := range srcs {
-				if strings.Contains(s, "/") {
-					return true
-				}
-			}
-		} else {
-			// srcs wasn't a list, check for a glob over subdirectory soruces
-			srcExp := rule.Attr("srcs")
-			call, ok := srcExp.(*build.CallExpr)
-			if ok {
-				callName, ok := call.X.(*build.Ident)
-				if ok {
-					if callName.Name == "glob" {
-						for _, arg := range call.List {
-							strArg, ok := arg.(*build.StringExpr)
-							if ok && strings.Contains(strArg.Value, "/") {
-								return true
-							}
-						}
-					}
-				}
-			}
-		}
-		// TODO(b/120783741):
-		// This only handles a lists of files, and a single glob, there are other
-		// cases such as a glob + a list of files that it doesn't handle, but that's
-		// ok since, this is only meant as a caution to the user.
-	}
-
-	return false
-}
-
-// directoryOrAncestorHasSubdirectorySources checks for ts_libraries referencing sources in subdirectories.
-// It checks the current directory's BUILD if it exists, otherwise it checks the nearest
-// ancestor package.
-func directoryOrAncestorHasSubdirectorySources(ctx context.Context, g3root, workspaceRelativePath string, bld *build.File) (bool, error) {
-	if bld == nil {
-		// Make sure the next closest ancestor package doesn't reference sources in a subdirectory.
-		ancestor, err := FindBUILDFile(ctx, make(map[string]*build.File), g3root, filepath.Dir(workspaceRelativePath))
-		if _, ok := err.(*noAncestorBUILDError); ok {
-			// couldn't find an ancestor BUILD, so there aren't an subdirectory sources
-			return false, nil
-		} else if err != nil {
-			return false, err
-		} else if hasSubdirectorySources(ancestor) {
-			return true, nil
-		} else {
-			// there was an ancestor BUILD, but it didn't reference subdirectory sources
-			return false, nil
-		}
-	}
-
-	if hasSubdirectorySources(bld) {
-		return true, nil
-	}
-
-	return false, nil
-}
-
-func (upd *Updater) addSourcesToBUILD(ctx context.Context, path string, buildFilePath string, bld *build.File, srcs srcSet) (bool, error) {
-
-	platform.Infof("Updating sources")
-	if len(srcs) == 0 && len(allTSRules(bld)) == 0 {
-		// No TypeScript rules/sources, no need to update anything
-		return false, nil
-	}
-	updateSources(bld, srcs)
-
-	return upd.maybeWriteBUILD(ctx, buildFilePath, bld)
-}
-
-// updateBUILDAfterBazelAnalyze applies the BUILD file updates that depend on bazel
-// analyze's DependencyReports, most notably updating any rules' deps.
-func (upd *Updater) updateBUILDAfterBazelAnalyze(ctx context.Context, isRoot bool,
-	g3root string, buildFilePath string, bld *build.File, reports []*arpb.DependencyReport) (bool, error) {
-	platform.Infof("Updating deps")
-	if err := updateDeps(bld, reports); err != nil {
-		return false, err
-	}
-
-	platform.Infof("Setting library rule kinds")
-	if err := setLibraryRuleKinds(ctx, buildFilePath, bld); err != nil {
-		return false, err
-	}
-	return upd.maybeWriteBUILD(ctx, buildFilePath, bld)
-}
-
-// IsTazeDisabledForDir checks if ts_auto_deps is disabled in the BUILD file in the dir,
-// or if no BUILD file exists, in the closest ancestor BUILD
-func IsTazeDisabledForDir(ctx context.Context, dir string) (bool, error) {
-	g3root, buildFilePath, workspaceRelativePath, err := getBUILDPath(ctx, dir)
-	if err != nil {
-		return false, err
-	}
-
-	bld, err := readBUILD(ctx, buildFilePath, workspaceRelativePath)
-	if err != nil {
-		platform.Infof("Error reading building file!")
-		return false, err
-	}
-
-	return isTazeDisabledInPackage(ctx, g3root, buildFilePath, workspaceRelativePath, bld)
-}
-
-// CantProgressAfterWriteError reports that ts_auto_deps was run in an environment
-// where it can't make writes to the file system (such as when ts_auto_deps is running
-// as a service for cider) and the writes it made need to be visible to bazel analyze,
-// so it can continue updating the BUILD file(s).  In such a case, the caller should
-// collect the writes using a custom UpdateFile function, and re-call ts_auto_deps after
-// applying the writes.
-type CantProgressAfterWriteError struct{}
-
-func (a *CantProgressAfterWriteError) Error() string {
-	return "running ts_auto_deps in a non-writable environment, can't continue until writes are applied"
-}
-
-// UpdateBUILDOptions bundles options for the UpdateBUILD function.
-type UpdateBUILDOptions struct {
-	// InNonWritableEnvironment boolean indicates to ts_auto_deps that the writes it makes
-	// won't be immediately visible to bazel analyze, so it cannot proceed normally.
-	// In this case, if it makes a write that needs to be visible to bazel analyze, it
-	// will return a CantProgressAfterWriteError, which indicates that the caller
-	// should apply the writes made to its UpdateFile function, and re-call UpdateBUILD
-	// after the writes have been applied.
-	InNonWritableEnvironment bool
-	// IsRoot indicates that the directory is a project's root directory, so a tsconfig
-	// rule should be created.
-	IsRoot bool
-}
-
-// LatencyReport contains timing measurements of the functions that are called
-// when running the presubmit on a package without any TypeScript (since we
-// return early to avoid the latency of RAS analyze).
-type LatencyReport struct {
-	GetBUILD, TazeDisabled, SubdirSrcs, AddSrcs time.Duration
-}
-
-// UpdateBUILD drives the main process of creating/updating the BUILD file
-// underneath path based on the available sources. Returns true if it modified
-// the BUILD file, false if the BUILD file was up to date already. bazelAnalyze
-// is used to run the underlying `bazel analyze` process.  Returns another
-// boolean that's true iff the package doesn't contain any TypeScript (source
-// files or BUILD rules).
-func (upd *Updater) UpdateBUILD(ctx context.Context, path string, options UpdateBUILDOptions) (bool, *LatencyReport, error) {
-	latencyReport := &LatencyReport{}
-
-	// asynchronously glob for TS sources in the package, since it can be slow on
-	// a network file system.
-	globChan := make(chan globResult)
-	go func() {
-		platform.Infof("Globbing TS sources in %s", path)
-		srcs, err := globSources(ctx, path, []string{"ts", "tsx"})
-		globChan <- globResult{srcs, err}
-	}()
-
-	start := time.Now()
-	g3root, buildFilePath, workspaceRelativePath, err := getBUILDPath(ctx, path)
-	if err != nil {
-		return false, nil, err
-	}
-
-	bld, err := readBUILD(ctx, buildFilePath, workspaceRelativePath)
-	if err != nil {
-		platform.Infof("Error reading building file!")
-		return false, nil, err
-	}
-	latencyReport.GetBUILD = time.Since(start)
-
-	start = time.Now()
-	ts_auto_depsDisabled, err := isTazeDisabledInPackage(ctx, g3root, buildFilePath, workspaceRelativePath, bld)
-	if err != nil {
-		return false, nil, err
-	}
-	latencyReport.TazeDisabled = time.Since(start)
-	if ts_auto_depsDisabled {
-		return false, nil, nil
-	}
-
-	start = time.Now()
-	hasSubdirSrcs, err := directoryOrAncestorHasSubdirectorySources(ctx, g3root, workspaceRelativePath, bld)
-	latencyReport.SubdirSrcs = time.Since(start)
-	if err != nil {
-		return false, nil, err
-	}
-	if hasSubdirSrcs {
-		return false, nil, &SubdirectorySourcesError{}
-	}
-
-	if bld == nil {
-		// The BUILD file didn't exist, so create a new, empty one.
-		bld = &build.File{Path: workspaceRelativePath, Type: build.TypeBuild}
-	}
-
-	start = time.Now()
-	globRes := <-globChan
-	if globRes.err != nil {
-		return false, nil, globRes.err
-	}
-	changed, err := upd.addSourcesToBUILD(ctx, path, buildFilePath, bld, globRes.srcs)
-	latencyReport.AddSrcs = time.Since(start)
-	if err != nil {
-		return false, nil, err
-	}
-	if options.InNonWritableEnvironment && changed {
-		return true, nil, &CantProgressAfterWriteError{}
-	}
-
-	rules := allTSRules(bld)
-	if len(rules) == 0 && !options.IsRoot {
-		// No TypeScript rules, no need to query for dependencies etc, so just exit early.
-		return changed, latencyReport, nil
-	}
-	rulesWithSrcs := []*build.Rule{}
-	for _, r := range rules {
-		srcs := r.Attr("srcs")
-		if srcs != nil {
-			if l, ok := srcs.(*build.ListExpr); ok && len(l.List) > 0 {
-				rulesWithSrcs = append(rulesWithSrcs, r)
-			}
-		}
-	}
-	platform.Infof("analyzing...")
-	reports, err := upd.runBazelAnalyze(buildFilePath, bld, rulesWithSrcs)
-	if err != nil {
-		return false, nil, err
-	}
-
-	changedAfterBazelAnalyze, err := upd.updateBUILDAfterBazelAnalyze(ctx, options.IsRoot, g3root, buildFilePath, bld, reports)
-	if err != nil {
-		return false, nil, err
-	}
-	changed = changed || changedAfterBazelAnalyze
-	if options.InNonWritableEnvironment && changed {
-		return true, nil, &CantProgressAfterWriteError{}
-	}
-
-	return changed, nil, nil
-}
-
-// buildHasDisableTaze checks if the BUILD file should be managed using ts_auto_deps.
-// Users can disable ts_auto_deps by adding a "disable_ts_auto_deps()" (or "dont_ts_auto_deps_me()") statement.
-func buildHasDisableTaze(bld *build.File) bool {
-	for _, stmt := range bld.Stmt {
-		if call, ok := stmt.(*build.CallExpr); ok {
-			if fnName, ok := call.X.(*build.Ident); ok && (fnName.Name == "disable_ts_auto_deps" || fnName.Name == "dont_ts_auto_deps_me") {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-// QueryBasedBazelAnalyze uses bazel query to analyze targets. It is available under a flag or
-// an environment variable on engineer's workstations.
-func QueryBasedBazelAnalyze(buildFilePath string, targets []string) ([]byte, []byte, error) {
-	root, err := workspace.Root(buildFilePath)
-	if err != nil {
-		return nil, nil, err
-	}
-	reports, err := analyze.New(analyze.NewQueryBasedTargetLoader(root, "bazel")).Analyze(context.Background(), buildFilePath, targets)
-	if err != nil {
-		return nil, nil, err
-	}
-	s, err := proto.Marshal(&arpb.AnalyzeResult{
-		DependencyReport: reports,
-	})
-	return s, nil, err
-}
-
-type ruleType int
-
-const (
-	ruleTypeAny ruleType = iota
-	ruleTypeRegular
-	ruleTypeTest
-	ruleTypeTestSupport
-)
-
-// isKind returns true if the rule has given kind.  It also accepts "ng_modules"
-// as "ts_library" kind.
-func isKind(r *build.Rule, kind string) bool {
-	acceptNgModule := kind == "ts_library"
-
-	return r.Kind() == kind || (acceptNgModule && r.Kind() == "ng_module")
-}
-
-func buildRules(bld *build.File, kind string) []*build.Rule {
-	// Find all rules, then filter by kind.
-	// This is nearly the same as just calling bld.Rules(kind), but allows to
-	// retrieve ng_module and ts_library intermixed, in the order in which they
-	// appear in the BUILD file. That allows ts_auto_deps to consistently always pick the
-	// last build rule in the file in case multiple match, regardless of kind.
-	allRules := bld.Rules("")
-	var res []*build.Rule
-	for _, r := range allRules {
-		if isKind(r, kind) {
-			res = append(res, r)
-		}
-	}
-	return res
-}
-
-// hasDependency returns whether a build rule contains the specified dependency.
-func hasDependency(bld *build.File, r *build.Rule, dep string) bool {
-	pkg := filepath.Dir(bld.Path)
-	oldDeps := r.Attr("deps")
-	if edit.ListFind(oldDeps, dep, pkg) != nil {
-		return true
-	}
-	runtimeDeps := r.Attr("runtime_deps")
-	return edit.ListFind(runtimeDeps, dep, pkg) != nil
-}
-
-// addDep adds a dependency to the specified build rule
-func addDep(bld *build.File, r *build.Rule, dep string) {
-	pkg := filepath.Dir(bld.Path)
-	dep = edit.ShortenLabel(dep, pkg)
-	if dep[0] != '/' && dep[0] != ':' {
-		dep = ":" + dep // ShortenLabel doesn't add the ':'
-	}
-	edit.AddValueToListAttribute(r, "deps", pkg, &build.StringExpr{Value: dep}, nil)
-}
-
-// AbsoluteBazelTarget converts a ruleName to an absolute target string (//foo/bar:bar).
-// It interprets ruleName relative to the given build file's package. It
-// supports plain names, names starting with colons, absolute paths, and
-// absolute paths with shorthand target syntax (i.e. "bar", ":bar", "//foo/bar",
-// "//foo/bar:bar").
-func AbsoluteBazelTarget(bld *build.File, ruleName string) string {
-	if strings.HasPrefix(ruleName, "//") {
-		// already absolute
-		if colonIdx := strings.LastIndex(ruleName, ":"); colonIdx == -1 {
-			// expand shorthand syntax
-			return ruleName + ":" + ruleName[strings.LastIndex(ruleName, "/")+1:]
-		}
-		return ruleName
-	}
-	pkg := platform.Normalize(filepath.Dir(bld.Path))
-	return fmt.Sprintf("//%s:%s", pkg, strings.TrimPrefix(ruleName, ":"))
-}
-
-// Finds all ts_library and ts_declaration targets in the given BUILD file.
-func allTSRules(bld *build.File) []*build.Rule {
-	var res []*build.Rule
-	res = append(res, buildRules(bld, "ts_library")...)
-	res = append(res, buildRules(bld, "ts_declaration")...)
-	return res
-}
-
-// removeSourcesUsed removes sources used by rules of kind ruleKind in attribute
-// attrName from the given set of sources.
-func removeSourcesUsed(bld *build.File, ruleKind, attrName string, srcs srcSet) {
-	for _, rule := range buildRules(bld, ruleKind) {
-		for s := range srcs {
-			pkg := filepath.Dir(bld.Path)
-			// Handles ":foo.ts" references, and concatenated lists [foo.ts] + [bar.ts]
-			// TODO(martinprobst): What to do about sources that don't seem to exist?
-			if edit.ListFind(rule.Attr(attrName), s, pkg) != nil {
-				delete(srcs, s)
-			}
-		}
-	}
-}
-
-const (
-	tsSkylarkLabel = "@npm_bazel_typescript//:index.bzl"
-	ngSkylarkLabel = "@angular//:index.bzl"
-)
-
-func removeUnusedLoad(bld *build.File, kind string) {
-	if len(bld.Rules(kind)) > 0 {
-		return // kind is still used somewhere.
-	}
-	var stmt []build.Expr
-	for _, s := range bld.Stmt {
-		load, ok := s.(*build.LoadStmt)
-		if !ok {
-			stmt = append(stmt, s)
-			continue
-		}
-		if len(load.To) == 0 {
-			// a load statement without actually loaded symbols, skip
-			continue
-		}
-
-		var from, to []*build.Ident
-		for i, ca := range load.To {
-			if ca.Name != kind {
-				from = append(from, load.From[i])
-				to = append(to, ca)
-			}
-		}
-		load.From = from
-		load.To = to
-		if len(to) > 0 {
-			stmt = append(stmt, load)
-			continue
-		}
-	}
-	bld.Stmt = stmt
-}
-
-// setLibraryRuleKinds sets the kinds for recognized library rules. That is, it
-// determines if a rule should be an ng_module, and sets the
-// rule kind if so. It also takes care of having the appropriate load calls.
-func setLibraryRuleKinds(ctx context.Context, buildFilePath string, bld *build.File) error {
-	hasNgModule := false
-	changed := false
-	for _, r := range buildRules(bld, "ts_library") {
-		shouldBeNgModule := false
-		isNgModule := r.Call.X.(*build.Ident).Name == "ng_module"
-		if hasAngularDependency(r) {
-			shouldBeNgModule = true
-			hasNgModule = true
-		}
-		if isNgModule && !shouldBeNgModule {
-			platform.Infof("Changing rule %s to ts_library()", r.AttrString("name"))
-			r.Call.X.(*build.Ident).Name = "ts_library"
-			r.DelAttr("assets")
-			changed = true
-		} else if !isNgModule && shouldBeNgModule {
-			platform.Infof("Changing rule %s to ng_module()", r.AttrString("name"))
-			r.Call.X.(*build.Ident).Name = "ng_module"
-			changed = true
-		}
-	}
-	if changed {
-		bld.Stmt = edit.InsertLoad(bld.Stmt, ngSkylarkLabel,
-			[]string{"ng_module"}, []string{"ng_module"})
-		bld.Stmt = edit.InsertLoad(bld.Stmt, tsSkylarkLabel,
-			[]string{"ts_library"}, []string{"ts_library"})
-		removeUnusedLoad(bld, "ts_library")
-		removeUnusedLoad(bld, "ng_module")
-	}
-	if !hasNgModule {
-		return nil
-	}
-	return updateWebAssets(ctx, buildFilePath, bld)
-}
-
-// hasAngularDependency returns true if the given rule depends on a Angular
-// build rule.
-func hasAngularDependency(r *build.Rule) bool {
-	e := r.Attr("deps")
-	for _, li := range edit.AllLists(e) {
-		for _, elem := range li.List {
-			str, ok := elem.(*build.StringExpr)
-			if ok && strings.HasPrefix(str.Value, "//third_party/javascript/angular2") {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-// updateWebAssets finds web assets in the package of the BUILD file and adds
-// them to the "assets" attribute of the ng_module rules.
-func updateWebAssets(ctx context.Context, buildFilePath string, bld *build.File) error {
-	// TODO(martinprobst): should this be merged with updateSources above? Difference is that
-	// creates new rules, this just distributes assets across them.
-	// This must use buildFilePath, the absolute path to the directory, as our cwd
-	// might not be the workspace root.
-	absolutePkgPath := filepath.Dir(buildFilePath)
-	assetFiles, err := globSources(ctx, absolutePkgPath, []string{"html", "css"})
-	if err != nil {
-		return err
-	}
-	platform.Infof("Found asset files in %s: %v", absolutePkgPath, assetFiles)
-
-	pkg := filepath.Dir(bld.Path)
-	for _, r := range bld.Rules("ng_module") {
-		srcs := r.Attr("assets")
-		if call, ok := srcs.(*build.CallExpr); ok && call.X.(*build.Ident).Name == "glob" {
-			// Remove any glob calls, ts_auto_deps uses explicit source lists.
-			r.DelAttr("assets")
-		}
-
-		for _, s := range r.AttrStrings("assets") {
-			if strings.HasPrefix(s, ":") || strings.HasPrefix(s, "//") {
-				continue // keep rule references
-			}
-			if _, ok := assetFiles[s]; !ok {
-				edit.ListAttributeDelete(r, "assets", s, pkg)
-			}
-		}
-	}
-
-	removeSourcesUsed(bld, "ng_module", "assets", assetFiles)
-	if len(assetFiles) == 0 {
-		return nil
-	}
-
-	// Add to the last rule, to match behaviour with *.ts sources.
-	lastModule := getLastRule(bld, "ng_module", ruleTypeRegular)
-	if lastModule == nil {
-		// Fall back to using any ng_module
-		lastModule = getLastRule(bld, "ng_module", ruleTypeAny)
-	}
-	if lastModule == nil {
-		// Should not happen by preconditions of this function.
-		return fmt.Errorf("no ng_module rules in BUILD?")
-	}
-
-	for newAsset := range assetFiles {
-		val := &build.StringExpr{Value: newAsset}
-		edit.AddValueToListAttribute(lastModule, "assets", pkg, val, nil)
-	}
-	return nil
-}
-
-// getOrCreateRule returns or creates a rule of the given kind, with testonly = 1 or 0 depending on
-// rt. If there's no such rule, it creates a new rule with the given ruleName.
-// If there is more than one rule matching, it returns the *last* rule.
-func getOrCreateRule(bld *build.File, ruleName, ruleKind string, rt ruleType) *build.Rule {
-	if r := getLastRule(bld, ruleKind, rt); r != nil {
-		return r
-	}
-
-	// TODO(calebegg): Switch this to "_test" but still support "_tests"
-	if rt == ruleTypeTest {
-		ruleName += "_tests"
-	}
-
-	loadArgs := []string{ruleKind}
-	bld.Stmt = edit.InsertLoad(bld.Stmt, tsSkylarkLabel, loadArgs, loadArgs)
-
-	r := &build.Rule{&build.CallExpr{X: &build.Ident{Name: ruleKind}}, ""}
-	// Rename to *_ts if there's a name collision. This leaves open a collision with another rule
-	// called _ts, but that failure mode is unlikely to happen accidentally.
-	if edit.FindRuleByName(bld, ruleName) != nil {
-		ruleName = ruleName + "_ts"
-	} else if filepath.Base(filepath.Dir(bld.Path)) == ruleName {
-		// The various *_ajd macros do not have a "name" attribute, but implicitly use the package name.
-		// Make sure not to use the package name if there is a *_ajd rule.
-		for _, r := range bld.Rules("") {
-			if r.Name() == "" && strings.HasSuffix(r.Kind(), "_ajd") {
-				ruleName = ruleName + "_ts"
-				break
-			}
-		}
-	}
-	r.SetAttr("name", &build.StringExpr{Value: ruleName})
-	if rt == ruleTypeTest || rt == ruleTypeTestSupport {
-		r.SetAttr("testonly", &build.Ident{Name: "True"})
-	}
-	bld.Stmt = append(bld.Stmt, r.Call)
-	return r
-}
-
-// ruleMatches return whether a rule matches the specified kind and rt value.
-func ruleMatches(bld *build.File, r *build.Rule, kind string, rt ruleType) bool {
-	if !isKind(r, kind) {
-		return false
-	}
-	inTestingDir := determineRuleType(bld.Path, "somefile.ts") == ruleTypeTestSupport
-	hasTestsName := strings.HasSuffix(r.Name(), "_tests")
-	// Accept the rule if it matches the testonly attribute.
-	if rt == ruleTypeAny {
-		return true
-	}
-	if attrTruthy(r, "testonly") {
-		if inTestingDir && ((hasTestsName && rt == ruleTypeTest) || (!hasTestsName && rt == ruleTypeTestSupport)) {
-			return true
-		}
-		if !inTestingDir && rt == ruleTypeTest {
-			return true
-		}
-	}
-	return rt == ruleTypeRegular && !attrTruthy(r, "testonly")
-}
-
-// targetRegisteredInRule returns whether a target has been registered in a rule that
-// matches a specified ruleKind and ruleType in current build file
-func targetRegisteredInRule(bld *build.File, ruleKind string, rt ruleType, target string) bool {
-	for _, r := range bld.Rules("") {
-		if ruleMatches(bld, r, ruleKind, rt) && hasDependency(bld, r, target) {
-			return true
-		}
-	}
-	return false
-}
-
-// getRule returns the last rule in bld that has the given ruleKind and matches
-// the specified rt value.
-func getLastRule(bld *build.File, ruleKind string, rt ruleType) *build.Rule {
-	rules := getRules(bld, ruleKind, rt)
-
-	if len(rules) == 0 {
-		return nil
-	}
-
-	return rules[len(rules)-1]
-}
-
-// getRules returns all the rules in bld that have the given ruleKind and
-// matches the specified rt value.
-func getRules(bld *build.File, ruleKind string, rt ruleType) []*build.Rule {
-	var rules []*build.Rule
-	for _, r := range bld.Rules("") {
-		if ruleMatches(bld, r, ruleKind, rt) {
-			rules = append(rules, r)
-		}
-	}
-
-	return rules
-}
-
-// FilterPaths filters the given paths, returning the deduplicated set of
-// folders that contain TypeScript sources (.ts and .tsx) or BUILD files.
-func FilterPaths(paths []string) []string {
-	fileSet := make(map[string]bool)
-	for _, p := range paths {
-		if !strings.HasSuffix(p, ".ts") && !strings.HasSuffix(p, ".tsx") && filepath.Base(p) != "BUILD" {
-			continue
-		}
-		fileSet[filepath.Dir(p)] = true
-	}
-	var newPaths []string
-	for k := range fileSet {
-		newPaths = append(newPaths, platform.Normalize(k))
-	}
-	return newPaths
-}
-
-// ResolvePackages resolves package paths, i.e. paths starting with '//',
-// against the workspace root folder closest to the current working directory.
-// It updates paths in place.
-// It returns an error if it cannot find a workspace root or working directory.
-func ResolvePackages(paths []string) error {
-	for i, p := range paths {
-		if strings.HasPrefix(p, "//") {
-			wd, err := os.Getwd()
-			if err != nil {
-				return fmt.Errorf("failed to get working directory: %v", err)
-			}
-			g3root, err := workspace.Root(wd)
-			if err != nil {
-				return fmt.Errorf("failed to find workspace root under %q: %v", wd, err)
-			}
-			paths[i] = filepath.Join(g3root, p)
-		}
-	}
-	return nil
-}
-
-type noAncestorBUILDError struct{}
-
-func (nabe *noAncestorBUILDError) Error() string {
-	return "no ancestor BUILD file found"
-}
-
-// FindBUILDFile searches for the closest parent BUILD file above pkg. It
-// returns the parsed BUILD file, or an error if none can be found.
-func FindBUILDFile(ctx context.Context, pkgToBUILD map[string]*build.File,
-	workspaceRoot string, packagePath string) (*build.File, error) {
-	if packagePath == "." || packagePath == "/" {
-		return nil, &noAncestorBUILDError{}
-	}
-	if bld, ok := pkgToBUILD[packagePath]; ok {
-		return bld, nil
-	}
-	buildPath := filepath.Join(workspaceRoot, packagePath, "BUILD")
-	bld, err := readBUILD(ctx, buildPath, filepath.Join(packagePath, "BUILD"))
-	if err != nil {
-		return nil, err
-	} else if bld == nil {
-		// Recursively search parent package and cache its location below if found.
-		bld, err = FindBUILDFile(ctx, pkgToBUILD, workspaceRoot, filepath.Dir(packagePath))
-	}
-	if err == nil {
-		// NB: The cache key is packagePath ('foo/bar/baz'), even if build file was
-		// found at a higher location ('foo/BUILD'). This avoids re-testing for file
-		// existence.
-		pkgToBUILD[packagePath] = bld
-	}
-	return bld, err
-}
-
-// Paths gets the list of paths for the current execution of ts_auto_deps.
-func Paths(isRoot bool, files bool, recursive bool) ([]string, error) {
-	paths := flag.Args()
-	if len(paths) == 0 {
-		wd, err := os.Getwd()
-		if err != nil {
-			return nil, fmt.Errorf("failed to get working directory: %v", err)
-		}
-		paths = []string{wd}
-	}
-
-	if len(paths) > 1 && isRoot {
-		return nil, fmt.Errorf("can only take exactly one path with -root")
-	}
-
-	if files {
-		paths = FilterPaths(paths)
-		if len(paths) == 0 {
-			return nil, fmt.Errorf("WARNING: found no TypeScript files in %s", paths)
-		}
-	}
-
-	if err := ResolvePackages(paths); err != nil {
-		return nil, fmt.Errorf("failed to resolve packages: %s", err)
-	}
-
-	if recursive {
-		var lock sync.Mutex // guards allPaths
-		var allPaths []string
-		for _, p := range paths {
-			err := platform.Walk(p, func(path string, info os.FileMode) error {
-				if info.IsDir() {
-					lock.Lock()
-					allPaths = append(allPaths, path)
-					lock.Unlock()
-				}
-				return nil
-			})
-			if err != nil {
-				return nil, fmt.Errorf("ts_auto_deps -recursive failed: %s", err)
-			}
-		}
-		sort.Sort(byLengthInverted(allPaths))
-		paths = allPaths
-	}
-
-	return paths, nil
-}
-
-// Execute runs ts_auto_deps on paths using host.
-func Execute(host *Updater, paths []string, isRoot, recursive bool) error {
-	ctx := context.Background()
-	for i, p := range paths {
-		isLastAndRoot := isRoot && i == len(paths)-1
-		changed, _, err := host.UpdateBUILD(ctx, p, UpdateBUILDOptions{InNonWritableEnvironment: false, IsRoot: isLastAndRoot})
-		if err != nil {
-			if recursive {
-				return fmt.Errorf("ts_auto_deps failed on %s/BUILD: %s", p, err)
-			}
-			return fmt.Errorf("ts_auto_deps failed: %s", err)
-		}
-		if changed {
-			if filepath.Base(p) == "BUILD" {
-				fmt.Printf("Wrote %s\n", p)
-			} else {
-				fmt.Printf("Wrote %s\n", filepath.Join(p, "BUILD"))
-			}
-		}
-	}
-	host.RegisterTestRules(ctx, paths...)
-	return nil
-}
-
-// allPaths walks the file system and returns a list of all directories under
-// all paths.
-func allPaths(paths []string) ([]string, error) {
-	var allPaths []string
-	for _, p := range paths {
-		err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
-			if err == nil && info.IsDir() {
-				allPaths = append(allPaths, path)
-			}
-			return err
-		})
-		if err != nil {
-			return nil, err
-		}
-	}
-	sort.Sort(byLengthInverted(allPaths))
-	return allPaths, nil
-}
-
-type byLengthInverted []string
-
-func (s byLengthInverted) Len() int           { return len(s) }
-func (s byLengthInverted) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-func (s byLengthInverted) Less(i, j int) bool { return len(s[i]) > len(s[j]) }
diff --git a/ts_auto_deps/updater/updater_test.go b/ts_auto_deps/updater/updater_test.go
deleted file mode 100644
index 613b99f..0000000
--- a/ts_auto_deps/updater/updater_test.go
+++ /dev/null
@@ -1,563 +0,0 @@
-package updater
-
-import (
-	"context"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-
-	"github.com/bazelbuild/buildtools/build"
-	"github.com/golang/protobuf/proto"
-
-	arpb "github.com/bazelbuild/rules_typescript/ts_auto_deps/proto"
-)
-
-var (
-	testTmpDir = os.Getenv("TEST_TMPDIR")
-)
-
-func mktmp(fn string, content []byte) (string, error) {
-	p := fn
-	if !filepath.IsAbs(p) {
-		p = filepath.Join(testTmpDir, fn)
-	}
-	if err := os.MkdirAll(filepath.Dir(p), 0777); err != nil {
-		return "", err
-	}
-	return p, ioutil.WriteFile(p, content, 0666)
-}
-
-func TestReadBuild(t *testing.T) {
-	p, err := mktmp("google3/foo/bar/BUILD", []byte(`
-ts_library(name = 'a', srcs = ['b.ts'])
-`))
-	if err != nil {
-		t.Fatal(err)
-	}
-	bld, err := readBUILD(context.Background(), p, "foo/bar/BUILD")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if bld.Path != "foo/bar/BUILD" {
-		t.Errorf("bld.Path: got %s, expected %s", bld.Path, "foo/bar/BUILD")
-	}
-}
-
-func TestGlobSources(t *testing.T) {
-	for _, f := range []string{"a.ts", "a/b.ts", "c.tsx", "whatever", "foo.cpp", "d.d.ts", "._e.ts"} {
-		if _, err := mktmp(f, []byte("// content")); err != nil {
-			t.Fatal(err)
-		}
-	}
-	if err := os.Symlink("../bazel-bin/symlink.d.ts", filepath.Join(testTmpDir, "symlink.d.ts")); err != nil {
-		t.Fatal(err)
-	}
-	if err := os.Symlink("whatever", filepath.Join(testTmpDir, "whatever.d.ts")); err != nil {
-		t.Fatal(err)
-	}
-	srcs, err := globSources(context.Background(), testTmpDir, []string{"ts", "tsx"})
-	if err != nil {
-		t.Fatal(err)
-	}
-	expected := srcSet(map[string]bool{
-		"a.ts":          true,
-		"c.tsx":         true,
-		"d.d.ts":        true,
-		"whatever.d.ts": true,
-	})
-	if !reflect.DeepEqual(srcs, expected) {
-		t.Errorf("globSources: got %v, want %v", srcs, expected)
-	}
-}
-
-func TestDetermineRuleType(t *testing.T) {
-	tests := []struct {
-		path   string
-		source string
-		rt     ruleType
-	}{
-		{"java/com/google/myapp/BUILD", "foo.ts", ruleTypeRegular},
-		{"java/com/google/myapp/BUILD", "foo_test.ts", ruleTypeTest},
-		{"java/com/google/myapp/BUILD", "foo_test.tsx", ruleTypeTest},
-
-		{"java/com/google/testing/mytesttool/BUILD", "foo.ts", ruleTypeRegular},
-		{"testing/mytesttool/BUILD", "foo.ts", ruleTypeRegular},
-		{"testing/mytesttool/BUILD", "foo_test.ts", ruleTypeTest},
-		{"testing/mytesttool/BUILD", "foo_test.ts", ruleTypeTest},
-	}
-	for _, tst := range tests {
-		rt := determineRuleType(tst.path, tst.source)
-		if rt != tst.rt {
-			t.Errorf("determineRuleType(%q, %q): got %v, expected %v", tst.path, tst.source, rt, tst.rt)
-		}
-	}
-}
-
-func parseReport(t *testing.T, input string) *arpb.DependencyReport {
-	report := &arpb.DependencyReport{}
-	if err := proto.UnmarshalText(input, report); err != nil {
-		t.Error(err)
-	}
-	return report
-}
-
-func TestBazelAnalyzeError(t *testing.T) {
-	bld, err := build.ParseBuild("rules/BUILD", []byte(`
-ts_library(
-	name = "firstrule",
-	srcs = [],
-)
-ts_library(
-	name = "secondrule",
-	srcs = [],
-)
-	`))
-	if err != nil {
-		t.Fatal(err)
-	}
-	mockAnalyze := func(_ string, targets []string) ([]byte, []byte, error) {
-		data, err := proto.Marshal(&arpb.AnalyzeResult{
-			DependencyReport: []*arpb.DependencyReport{&arpb.DependencyReport{
-				Rule: proto.String("//rules:firstrule"),
-			}},
-		})
-		return data, []byte(`Here's the actual error`), err
-	}
-	upd := &Updater{}
-	upd.bazelAnalyze = mockAnalyze
-	report, err := upd.runBazelAnalyze("firstrule/BUILD", bld, bld.Rules("ts_library"))
-	if err == nil {
-		t.Fatalf("expected an error, got a report: %v", report)
-	}
-	expected := `parsing reports failed (1 reports for [//rules:firstrule //rules:secondrule]):
-Here's the actual error`
-	if err.Error() != expected {
-		t.Errorf("runBazelAnalyze: got %q, expected %q", err.Error(), expected)
-	}
-}
-
-func TestUpdateDeps(t *testing.T) {
-	report := parseReport(t, `
-			rule: "//foo:bar"
-			unnecessary_dependency: "//unnecessary_dep"
-			missing_dependency_group: {
-				dependency: "//missing_dep"
-			}
-			missing_source_file: "missing_file.ts"`)
-
-	tests := []struct {
-		name    string
-		before  string
-		after   string
-		changed bool
-	}{
-		{
-			"Add missing dependency",
-			`ts_library(
-					name = "bar",
-					deps = [],
-			)`,
-			`ts_library(
-					name = "bar",
-					deps = ["//missing_dep"],
-			)`,
-			true,
-		},
-		{
-			"Remove + Add dependency",
-			`ts_library(
-					name = "bar",
-					deps = ["//unnecessary_dep"],
-			)`,
-			`ts_library(
-					name = "bar",
-					deps = ["//missing_dep"],
-			)`,
-			true,
-		},
-		{
-			"Remove nonexistent dep (e.g. due to macro)",
-			`ts_library(
-					name = "bar",
-					deps = ["//missing_dep"],
-			)`,
-			`ts_library(
-					name = "bar",
-					deps = ["//missing_dep"],
-			)`,
-			false, // Unchanged!
-		},
-		{
-			"Remove nonexistent src",
-			`ts_library(
-					name = "bar",
-					srcs = ["hello.ts"],
-					deps = ["//missing_dep"],
-			)`,
-			`ts_library(
-					name = "bar",
-					srcs = ["hello.ts"],
-					deps = ["//missing_dep"],
-			)`,
-			false, // Unchanged!
-		},
-	}
-	for _, tst := range tests {
-		bld, err := build.ParseBuild("foo/BUILD", []byte(tst.before))
-		if err != nil {
-			t.Errorf("parse %s failed: %s in %s", tst.name, err, tst.before)
-		}
-		bldAft, err := build.ParseBuild("foo/BUILD", []byte(tst.after))
-		if err != nil {
-			t.Errorf("parse %s after failed: %s", tst.name, err)
-		}
-		if err := updateDeps(bld, []*arpb.DependencyReport{report}); err != nil {
-			t.Errorf("update %s failed: %s", tst.name, err)
-		}
-		updated := string(build.Format(bld))
-		after := string(build.Format(bldAft))
-		if updated != after {
-			t.Errorf("update(%s), got:\n%s\n\nexpected:\n%s", tst.name, updated, after)
-		}
-	}
-}
-
-func TestUnresolvedImportError(t *testing.T) {
-	report := parseReport(t, `
-			rule: "//foo:bar"
-			unresolved_import: "unresolved/import"`)
-
-	bld, err := build.ParseBuild("foo/BUILD", []byte(`ts_library(
-					name = "bar",
-					srcs = ["hello.ts"],
-			)`))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	expectedErr := "'// from ...'' comment, or the target BUILD files are incorrect?"
-
-	err = updateDeps(bld, []*arpb.DependencyReport{report})
-	if !strings.Contains(err.Error(), expectedErr) {
-		t.Errorf("returned error %s: expected it to contain %s", err, expectedErr)
-	}
-}
-
-func TestDottedCall(t *testing.T) {
-	// Repro for a crash, b/35389044
-	buildText := `foo.bar("baz")`
-	bld, err := build.ParseBuild("test", []byte(buildText))
-	if err != nil {
-		t.Error(err)
-	}
-	removeUnusedLoad(bld, "ignored")
-}
-
-func TestFilterPaths(t *testing.T) {
-	tests := []struct {
-		in       []string
-		expected []string
-	}{
-		{[]string{"foo/bar.txt", "foo/baz.ts"}, []string{"foo"}},
-		{[]string{"bam.ts"}, []string{"."}},
-		{[]string{"foo/BUILD"}, []string{"foo"}},
-		{[]string{"r/foo.tsx"}, []string{"r"}},
-		{[]string{"../../x.ts"}, []string{"../.."}},
-		{[]string{"a.txt", "foo/b.txt"}, []string(nil)},
-	}
-	for _, tst := range tests {
-		res := FilterPaths(tst.in)
-		if !reflect.DeepEqual(res, tst.expected) {
-			t.Errorf("FilterPaths(%v): got %v, expected %v", tst.in, res, tst.expected)
-		}
-	}
-}
-
-func TestAddDep(t *testing.T) {
-	tests := []struct {
-		buildFile string
-		newDep    string
-		expected  string
-	}{
-		{`ts_library(name = "lib", deps = ["//a", "//b", "//c"])`,
-			"//b",
-			`ts_library(name = "lib", deps = ["//a", "//b", "//c"])`},
-		{`ts_library(name = "lib", deps = ["//a", "//b", "//c"])`,
-			"//d",
-			`ts_library(name = "lib", deps = ["//a", "//b", "//c", "//d"])`},
-		{`ts_library(name = "lib", deps = ["//a", ":b", "//c"])`,
-			":b",
-			`ts_library(name = "lib", deps = ["//a", ":b", "//c"])`},
-		{`ts_library(name = "lib", deps = ["//a", ":b", "//c"])`,
-			"//buildloc:b",
-			`ts_library(name = "lib", deps = ["//a", ":b", "//c"])`},
-		{`ts_library(name = "lib", deps = ["//a", "//buildloc:b", "//c"])`,
-			":b",
-			`ts_library(name = "lib", deps = ["//a", "//buildloc:b", "//c"])`},
-		{`ts_library(name = "lib", deps = ["//a", "//other:b", "//c"])`,
-			":b",
-			`ts_library(name = "lib", deps = [":b", "//a", "//other:b", "//c"])`},
-		{`ts_library(name = "lib", deps = ["//a", "//other:b", "//c"])`,
-			"//a:a",
-			`ts_library(name = "lib", deps = ["//a", "//other:b", "//c"])`},
-	}
-	for _, tst := range tests {
-		bld, err := build.ParseBuild("buildloc/BUILD", []byte(tst.buildFile))
-		if err != nil {
-			t.Fatalf("parse failure: %s - %v", tst.buildFile, err)
-		}
-		addDep(bld, bld.Rules("ts_library")[0], tst.newDep)
-		newContent := string(build.Format(bld))
-		expectedBld, err := build.ParseBuild("buildloc/BUILD", []byte(tst.expected))
-		if err != nil {
-			t.Fatalf("parse failure: %s - %v", tst.expected, err)
-		}
-		expected := string(build.Format(expectedBld))
-		if newContent != expected {
-			t.Errorf("addDep(%s, %s): got %v, expected %v", tst.buildFile, tst.newDep, newContent, tst.expected)
-		}
-	}
-}
-
-func TestRemoveSourcesUsed(t *testing.T) {
-	tests := []struct {
-		name         string
-		buildFile    string
-		ruleKind     string
-		attrName     string
-		srcs         srcSet
-		expectedSrcs srcSet
-	}{
-		{
-			name:         "RemovesSources",
-			buildFile:    `ts_library(name = "lib", srcs = ["foo.ts", "bar.ts"])`,
-			ruleKind:     "ts_library",
-			attrName:     "srcs",
-			srcs:         map[string]bool{"foo.ts": true},
-			expectedSrcs: map[string]bool{},
-		},
-		{
-			name:         "WrongRuleKind",
-			buildFile:    `ts_library(name = "lib", srcs = ["foo.ts", "bar.ts"])`,
-			ruleKind:     "ng_module",
-			attrName:     "srcs",
-			srcs:         map[string]bool{"foo.ts": true},
-			expectedSrcs: map[string]bool{"foo.ts": true},
-		},
-		{
-			name:         "WrongAttrName",
-			buildFile:    `ts_library(name = "lib", srcs = ["foo.ts", "bar.ts"])`,
-			ruleKind:     "ts_library",
-			attrName:     "deps",
-			srcs:         map[string]bool{"foo.ts": true},
-			expectedSrcs: map[string]bool{"foo.ts": true},
-		},
-		{
-			name: "MultipleRules",
-			buildFile: `ts_library(name = "lib", srcs = ["foo.ts"])
-			ts_library(name = "lib2", srcs = ["bar.ts"])`,
-			ruleKind:     "ts_library",
-			attrName:     "srcs",
-			srcs:         map[string]bool{"foo.ts": true, "bar.ts": true},
-			expectedSrcs: map[string]bool{},
-		},
-		{
-			name:         "ConcatenatedLists",
-			buildFile:    `ts_library(name = "lib", srcs = ["foo.ts"] + ["bar.ts"])`,
-			ruleKind:     "ts_library",
-			attrName:     "srcs",
-			srcs:         map[string]bool{"foo.ts": true, "bar.ts": true},
-			expectedSrcs: map[string]bool{},
-		},
-		{
-			name:         "ColonReferences",
-			buildFile:    `ts_library(name = "lib", srcs = [":foo.ts", "bar.ts"])`,
-			ruleKind:     "ts_library",
-			attrName:     "srcs",
-			srcs:         map[string]bool{"foo.ts": true},
-			expectedSrcs: map[string]bool{},
-		},
-	}
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			bld, err := build.ParseBuild("foo/bar/BUILD",
-				[]byte(test.buildFile))
-			if err != nil {
-				t.Fatalf("parse failure: %v", err)
-			}
-
-			removeSourcesUsed(bld, test.ruleKind, test.attrName, test.srcs)
-			if !reflect.DeepEqual(test.srcs, test.expectedSrcs) {
-				t.Errorf("expected removeSourcesUsed() = %v, expected %v", test.srcs, test.expectedSrcs)
-			}
-		})
-	}
-}
-
-func TestUpdateWebAssets(t *testing.T) {
-	ctx := context.Background()
-	bld, err := build.ParseBuild("foo/bar/BUILD",
-		[]byte(`ng_module(name = "m", assets = [":rule", "gone.html"])`))
-	if err != nil {
-		t.Fatalf("parse failure: %v", err)
-	}
-	testHTML, err := mktmp("google3/foo/bar/test.html", []byte(`<p>test</p>`))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		if err := os.Remove(testHTML); err != nil {
-			t.Error(err)
-		}
-	}()
-	testCSS, err := mktmp("google3/foo/bar/test.css", []byte(`.test {}`))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		if err := os.Remove(testCSS); err != nil {
-			t.Error(err)
-		}
-	}()
-	absoluteBuildPath := filepath.Join(filepath.Dir(testCSS), "BUILD")
-	if err := updateWebAssets(ctx, absoluteBuildPath, bld); err != nil {
-		t.Fatal(err)
-	}
-	data := string(build.Format(bld))
-	expected := `ng_module(
-    name = "m",
-    assets = [
-        ":rule",
-        "test.css",
-        "test.html",
-    ],
-)
-`
-	if data != expected {
-		t.Errorf("build file mismatch, got %s, expected %s", data, expected)
-	}
-}
-
-func TestWebAssetReferredByColon(t *testing.T) {
-	ctx := context.Background()
-	bld, err := build.ParseBuild("foo/bar/BUILD",
-		[]byte(`ng_module(name = "m", assets = [":colon.html"])`))
-	if err != nil {
-		t.Fatalf("parse failure: %v", err)
-	}
-	colon, err := mktmp("google3/foo/bar/colon.html", []byte(`<p>test</p>`))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		if err := os.Remove(colon); err != nil {
-			t.Error(err)
-		}
-	}()
-	absolutBuildPath := filepath.Join(filepath.Dir(colon), "BUILD")
-	if err := updateWebAssets(ctx, absolutBuildPath, bld); err != nil {
-		t.Error(err)
-	}
-	data := string(build.Format(bld))
-	expected := `ng_module(
-    name = "m",
-    assets = [":colon.html"],
-)
-`
-	if data != expected {
-		t.Errorf("build file mismatch, got %s, expected %s", data, expected)
-	}
-}
-
-func TestAbsoluteBazelTarget(t *testing.T) {
-	bld := &build.File{Path: "foo/bar/BUILD", Type: build.TypeBuild}
-	tests := []struct{ target, expected string }{
-		{"//foo/bar:bar", "//foo/bar:bar"},
-		{":bar", "//foo/bar:bar"},
-		{"bar", "//foo/bar:bar"},
-		{"//foo/bar", "//foo/bar:bar"},
-	}
-	for _, tst := range tests {
-		abs := AbsoluteBazelTarget(bld, tst.target)
-		if abs != tst.expected {
-			t.Errorf("AbsoluteBazelTarget(%q): got %q, expected %q", tst.target, abs, tst.expected)
-		}
-	}
-}
-
-func TestFindBUILDFileCacheOnError(t *testing.T) {
-	ctx := context.Background()
-	cache := make(map[string]*build.File)
-	p, err := mktmp("google3/pkg/file", []byte(""))
-	if err != nil {
-		t.Fatal(err)
-	}
-	g3root := filepath.Dir(filepath.Dir(p))
-	if filepath.Base(g3root) != "google3" {
-		t.Errorf("g3root should be called google3, got %q", g3root)
-	}
-	// No BUILD file was created in the file system so FindBUILDFile should
-	// return an error.
-	if _, err = FindBUILDFile(ctx, cache, g3root, "pkg"); err == nil {
-		t.Fatalf("returned no error, expected some error to occur")
-	}
-	if _, ok := cache["pkg"]; ok {
-		t.Fatalf("cache contained BUILD file for package")
-	}
-}
-
-func TestHasSubdirectorySources(t *testing.T) {
-	tests := []struct {
-		name      string
-		buildFile string
-		expected  bool
-	}{
-		{
-			name:      "LocalSources",
-			buildFile: `ts_library(name = "lib", srcs = ["foo.ts", "bar.ts"])`,
-			expected:  false,
-		},
-		{
-			name:      "SubdirectorySources",
-			buildFile: `ts_library(name = "lib", srcs = ["subdir/foo.ts", "subdir/bar.ts"])`,
-			expected:  true,
-		},
-		{
-			name:      "LocalNgModuleSources",
-			buildFile: `ng_module(name = "lib", srcs = ["foo.ts", "bar.ts"])`,
-			expected:  false,
-		},
-		{
-			name:      "SubdirectoryNgModuleSources",
-			buildFile: `ng_module(name = "lib", srcs = ["subdir/foo.ts", "subdir/bar.ts"])`,
-			expected:  true,
-		},
-		{
-			name:      "LocalGlob",
-			buildFile: `ts_library(name = "lib", srcs = glob("*.ts"))`,
-			expected:  false,
-		},
-		{
-			name:      "SubdirectoryGlob",
-			buildFile: `ts_library(name = "lib", srcs = glob("**/*.ts"))`,
-			expected:  true,
-		},
-	}
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			bld, err := build.ParseBuild("foo/bar/BUILD",
-				[]byte(test.buildFile))
-			if err != nil {
-				t.Fatalf("parse failure: %v", err)
-			}
-
-			actual := hasSubdirectorySources(bld)
-			if actual != test.expected {
-				t.Errorf("got hasSubdirectorySouces() = %v, expected %v", actual, test.expected)
-			}
-		})
-	}
-}
diff --git a/ts_auto_deps/workspace/BUILD.bazel b/ts_auto_deps/workspace/BUILD.bazel
deleted file mode 100644
index 38f8123..0000000
--- a/ts_auto_deps/workspace/BUILD.bazel
+++ /dev/null
@@ -1,9 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
-    name = "go_default_library",
-    srcs = ["workspace.go"],
-    importpath = "github.com/bazelbuild/rules_typescript/ts_auto_deps/workspace",
-    visibility = ["//visibility:public"],
-    deps = ["@com_github_bazelbuild_buildtools//wspace:go_default_library"],
-)
diff --git a/ts_auto_deps/workspace/workspace.go b/ts_auto_deps/workspace/workspace.go
deleted file mode 100644
index c7f1ac2..0000000
--- a/ts_auto_deps/workspace/workspace.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package workspace
-
-import "github.com/bazelbuild/buildtools/wspace"
-
-// Root finds the closest directory containing a WORKSPACE file from p.
-func Root(p string) (string, error) {
-	return wspace.Find(p)
-}
-
-// Name returns the name of the workspace.
-func Name() string {
-	return "TODO"
-}