Modify the query-based analyzer to handle cases where a source file is included in the srcs attribute of more than one rule.

Add a heuristic that if more that one rule supplies a source file, favor ts_library rules.

PiperOrigin-RevId: 236163673
diff --git a/ts_auto_deps/analyze/loader.go b/ts_auto_deps/analyze/loader.go
index ca5f73f..d522017 100644
--- a/ts_auto_deps/analyze/loader.go
+++ b/ts_auto_deps/analyze/loader.go
@@ -203,32 +203,37 @@
 		}
 	}
 
-	filepathToRule := make(map[string]*appb.Rule)
+	filepathToRules := make(map[string][]*appb.Rule)
 
 	// load all the rules with file srcs (either literal or generated)
-	sourceLabelToRule, err := q.loadRulesWithSources(workspaceRoot, fileLabels)
+	sourceLabelToRules, err := q.loadRulesWithSources(workspaceRoot, fileLabels)
 	if err != nil {
 		return nil, err
 	}
-	for label, rule := range sourceLabelToRule {
-		filepathToRule[labelToPath(label)] = rule
+	for label, rules := range sourceLabelToRules {
+		for _, rule := range rules {
+			filepathToRules[labelToPath(label)] = append(filepathToRules[labelToPath(label)], rule)
+		}
 	}
 
 	// load all the rules with generator rule srcs
-	generatorLabelToRule, err := q.loadRulesWithSources(workspaceRoot, generators)
+	generatorLabelToRules, err := q.loadRulesWithSources(workspaceRoot, generators)
 	if err != nil {
 		return nil, err
 	}
-	for label, rule := range generatorLabelToRule {
-		for _, generated := range generatorsToFiles[label] {
-			filepathToRule[labelToPath(generated.GetName())] = rule
+	for label, rules := range generatorLabelToRules {
+		for _, rule := range rules {
+			for _, generated := range generatorsToFiles[label] {
+				filepathToRules[labelToPath(generated.GetName())] = append(filepathToRules[labelToPath(generated.GetName())], rule)
+			}
 		}
 	}
 
 	for _, path := range paths {
 		// check all the possible file paths for the import path
 		for _, fp := range possibleFilepaths(path) {
-			if rule, ok := filepathToRule[fp]; ok {
+			if rules, ok := filepathToRules[fp]; ok {
+				rule := chooseCanonicalRule(rules)
 				results[path] = rule
 			}
 		}
@@ -237,6 +242,23 @@
 	return results, nil
 }
 
+// chooseCanonicalRule chooses between rules which includes the imported file as
+// a source.  It applies heuristics, such as prefering ts_library to other rule
+// types to narrow down the choices.  After narrowing, it chooses the first
+// rule.  If no rules are left after narrowing, it returns the first rule from
+// the original list.
+func chooseCanonicalRule(rules []*appb.Rule) *appb.Rule {
+	// filter down to only ts_library rules
+	for _, r := range rules {
+		if r.GetRuleClass() == "ts_library" {
+			return r
+		}
+	}
+
+	// if no rules matched the filter, just return the first rule
+	return rules[0]
+}
+
 // 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) {
@@ -279,10 +301,10 @@
 }
 
 // loadRulesWithSources loads all rules which include the labels in sources as
-// srcs attributes. Returns a map from source label to the rule which includes
-// it.  A source label can be the label of a source file or a generated file or
-// a generating rule.
-func (q *QueryBasedTargetLoader) loadRulesWithSources(workspaceRoot string, sources []string) (map[string]*appb.Rule, error) {
+// srcs attributes. Returns a map from source label to a list of rules which
+// include it.  A source label can be the label of a source file or a generated
+// file or a generating rule.
+func (q *QueryBasedTargetLoader) loadRulesWithSources(workspaceRoot string, sources []string) (map[string][]*appb.Rule, error) {
 	pkgToLabels := make(map[string][]string)
 	queries := make([]string, 0, len(sources))
 	for _, label := range sources {
@@ -295,7 +317,7 @@
 	if err != nil {
 		return nil, err
 	}
-	labelToRule := make(map[string]*appb.Rule)
+	labelToRules := make(map[string][]*appb.Rule)
 	for _, target := range r.GetTarget() {
 		label, err := q.ruleLabel(target)
 		if err != nil {
@@ -307,13 +329,13 @@
 		for _, src := range listAttribute(rule, "srcs") {
 			for _, l := range labels {
 				if src == l {
-					labelToRule[l] = rule
+					labelToRules[l] = append(labelToRules[l], rule)
 					break
 				}
 			}
 		}
 	}
-	return labelToRule, nil
+	return labelToRules, nil
 }
 
 // batchQuery runs a set of queries with a single call to Bazel query and the