Allow for ts strictdeps to look at multiple declaration sites of a symbol PiperOrigin-RevId: 290365047
diff --git a/internal/tsc_wrapped/strict_deps.ts b/internal/tsc_wrapped/strict_deps.ts index c2cb723..447fc3e 100644 --- a/internal/tsc_wrapped/strict_deps.ts +++ b/internal/tsc_wrapped/strict_deps.ts
@@ -85,15 +85,24 @@ if (!sym || !sym.declarations || sym.declarations.length < 1) { continue; } - // Module imports can only have one declaration location. - const declFileName = sym.declarations[0].getSourceFile().fileName; - if (allowedMap[stripExt(declFileName)]) continue; - const importName = path.posix.relative(rootDir, declFileName); + const declFileNames = + sym.declarations.map(decl => decl.getSourceFile().fileName); + if (declFileNames.find( + declFileName => !!allowedMap[stripExt(declFileName)])) { + continue; + } + const importNames = declFileNames.map( + declFileName => path.posix.relative(rootDir, declFileName)); + + const extraDeclarationLocationsMessage = (importNames.length < 2) ? + '' : + `(It is also declared in ${importNames.slice(1).join(', ')}) `; result.push({ file: sf, start: modSpec.getStart(), length: modSpec.getEnd() - modSpec.getStart(), - messageText: `transitive dependency on ${importName} not allowed. ` + + messageText: `transitive dependency on ${importNames[0]} not allowed. ` + + extraDeclarationLocationsMessage + `Please add the BUILD target to your rule's deps.`, category: ts.DiagnosticCategory.Error, // semantics are close enough, needs taze.
diff --git a/internal/tsc_wrapped/strict_deps_test.ts b/internal/tsc_wrapped/strict_deps_test.ts index 807e86e..1e3ae47 100644 --- a/internal/tsc_wrapped/strict_deps_test.ts +++ b/internal/tsc_wrapped/strict_deps_test.ts
@@ -132,4 +132,26 @@ expect(diags[0].messageText) .toMatch(/dependency on blaze-bin\/p\/sd1.d.ts not allowed/); }); + + it('allows multiple declarations of the same clutz-generated module', () => { + const p = createProgram({ + '/src/blaze-bin/p/js1.d.ts': `declare module 'goog:thing' {}`, + '/src/blaze-bin/p/js2.d.ts': `declare module 'goog:thing' {}`, + '/src/blaze-bin/p/js3.d.ts': `declare module 'goog:thing' {}`, + // Import from the middle one, to be sure it doesn't pass just because the + // order so happens that we checked the declaration from the first one + '/src/p/my.ts': `import {} from 'goog:thing'; // taze: from //p:js2`, + }); + const good = checkModuleDeps( + p.getSourceFile('/src/p/my.ts')!, p.getTypeChecker(), + ['/src/blaze-bin/p/js2.d.ts'], '/src'); + expect(good.length).toBe(0); + + const bad = checkModuleDeps( + p.getSourceFile('/src/p/my.ts')!, p.getTypeChecker(), [], '/src'); + expect(bad.length).toBe(1); + expect(bad[0].messageText) + .toContain( + '(It is also declared in blaze-bin/p/js2.d.ts, blaze-bin/p/js3.d.ts)'); + }); });