Check existing dependencies for ambient module declarations. PiperOrigin-RevId: 233083308
diff --git a/ts_auto_deps/analyze/analyze.go b/ts_auto_deps/analyze/analyze.go index 644110a..0960b57 100644 --- a/ts_auto_deps/analyze/analyze.go +++ b/ts_auto_deps/analyze/analyze.go
@@ -7,6 +7,7 @@ "fmt" "os" "path/filepath" + "regexp" "strings" "github.com/bazelbuild/buildtools/edit" @@ -327,7 +328,7 @@ continue handlingImports } } - d, err := a.findRuleProvidingImport(target.dependencies, imp) + d, err := a.findExistingDepProvidingImport(ctx, target.dependencies, imp) if err != nil { return err } @@ -368,22 +369,27 @@ return paths } -// findRuleProvidingImport looks through a map of loaded rules for a rule -// which can provide the passed import. +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) findRuleProvidingImport(rules map[string]*appb.Rule, i *ts_auto_depsImport) (string, error) { +func (a *Analyzer) findExistingDepProvidingImport(ctx context.Context, rules map[string]*appb.Rule, 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 rules { moduleName := stringAttribute(r, "module_name") if moduleName == "" { continue } - srcs := listAttribute(r, "srcs") - for _, src := range srcs { + for _, src := range listAttribute(r, "srcs") { _, _, file := edit.ParseLabel(src) moduleImportPath := moduleName + "/" + stripTSExtension(file) if i.importPath == moduleImportPath || i.importPath == strings.TrimSuffix(moduleImportPath, "/index") { @@ -391,6 +397,41 @@ } } } + + // check if any of the existing deps have .d.ts sources which have ambient module + // declarations + for _, r := range rules { + for _, src := range listAttribute(r, "srcs") { + filepath := labelToPath(src) + if !strings.HasSuffix(filepath, ".d.ts") { + continue + } + + contents, err := platform.ReadFile(ctx, filepath) + if err != nil { + return "", fmt.Errorf("error reading file lookinf 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(filepath, 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 }