Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 5dd76b4

Browse files
frigus02copybara-github
authored andcommitted
Emit side-effect imports for global dts from Clutz externs
Clutz is soon going to emit type declarations for externs in the global namespace. To make type annotations using externs work in transitive dependencies, tsickle needs to emit side effect imports in .d.ts files. This follows what tsickle is already doing for symbols from goog modules. PiperOrigin-RevId: 483933310
1 parent 196f96e commit 5dd76b4

12 files changed

+84
-24
lines changed

src/clutz.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
*/
1717

1818
import * as ts from 'typescript';
19+
1920
import * as googmodule from './googmodule';
2021
import * as path from './path';
22+
import {isDeclaredInClutzDts} from './type_translator';
2123

2224
/**
2325
* Constructs a ts.CustomTransformerFactory that postprocesses the .d.ts
@@ -317,25 +319,24 @@ function ambientModuleSymbolFromClutz(
317319
* because sometimes TS generates AST nodes that don't have a parent.
318320
*/
319321
function clutzSymbolFromQualifiedName(
320-
typeChecker: ts.TypeChecker, qname: ts.QualifiedName): ts.Symbol|undefined {
321-
// Verify that the innermost reference is the look of disapproval.
322-
let inner = qname;
323-
while (ts.isQualifiedName(inner.left)) {
324-
inner = inner.left;
325-
}
326-
if (inner.left.text !== 'ಠ_ಠ' || inner.right.text !== 'clutz') {
327-
return undefined; // Not a look of disapproval.
328-
}
329-
330-
const node = qname.right;
322+
typeChecker: ts.TypeChecker, name: ts.EntityName): ts.Symbol|undefined {
323+
const node = ts.isQualifiedName(name) ? name.right : name;
331324
let sym = typeChecker.getSymbolAtLocation(node);
332325
if (!sym) {
333326
// When the declarations transformer has synthesized a reference, for
334327
// example due to inference, the type checker will not return a symbol
335328
// underlying the node. Instead we reach through the TS internals for this.
329+
// Note: Even though TypeScript declares node.symbol as always defined,
330+
// we've seen instances of it being undefined.
336331
// tslint:disable-next-line:no-any circumventing private API
337-
sym = (node as any)['symbol'] as ts.Symbol;
332+
sym = (node as any)['symbol'] as ts.Symbol | undefined;
338333
}
334+
335+
if (!sym || !sym.declarations || sym.declarations.length === 0 ||
336+
!isDeclaredInClutzDts(sym.declarations[0])) {
337+
return undefined;
338+
}
339+
339340
return sym;
340341
}
341342

@@ -345,11 +346,11 @@ function clutzSymbolFromQualifiedName(
345346
*/
346347
function clutzSymbolFromNode(
347348
typeChecker: ts.TypeChecker, node: ts.Node): ts.Symbol|undefined {
348-
if (ts.isTypeReferenceNode(node) && ts.isQualifiedName(node.typeName)) {
349+
if (ts.isTypeReferenceNode(node)) {
349350
// Reference in type position.
350351
return clutzSymbolFromQualifiedName(typeChecker, node.typeName);
351352
}
352-
if (ts.isTypeQueryNode(node) && ts.isQualifiedName(node.exprName)) {
353+
if (ts.isTypeQueryNode(node)) {
353354
// Reference in typeof position.
354355
return clutzSymbolFromQualifiedName(typeChecker, node.exprName);
355356
}
@@ -403,9 +404,8 @@ function gatherNecessaryClutzImports(typeChecker: ts.TypeChecker, sf: ts.SourceF
403404

404405

405406
/**
406-
* Recursively searches a node for references to members of the `ಠ_ಠ.clutz`
407-
* namespace, and adds any referenced source files to the `imports` set.
408-
* TODO(b/162295026): forbid this pattern and delete this logic.
407+
* Recursively searches a node for references to symbols declared in Clutz
408+
* .d.ts files and adds any referenced source files to the `imports` set.
409409
*/
410410
function visit(node: ts.Node) {
411411
const sym = clutzSymbolFromNode(typeChecker, node);

src/type_translator.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ export function isDeclaredInBuiltinLibDTS(node: ts.Node|null|
4545
* Returns true if the given node's source file is generated by Clutz, i.e. has
4646
* the magic Clutz header.
4747
*/
48-
function isDeclaredInClutzDts(node: ts.Node|null|undefined): boolean {
48+
export function isDeclaredInClutzDts(node: ts.Node|null|undefined): boolean {
4949
const sourceFile = node?.getSourceFile();
50-
return !!sourceFile && sourceFile.text.startsWith('//!! generated by clutz.');
50+
if (!sourceFile) return false;
51+
const clutz1Header = '//!! generated by clutz.';
52+
const clutz2Header = '// Generated by google3/javascript/typescript/clutz2';
53+
return sourceFile.text.startsWith(clutz1Header) ||
54+
sourceFile.text.startsWith(clutz2Header);
5155
}
5256

5357
/**
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Generated by google3/javascript/typescript/clutz2
2+
/**
3+
* @fileoverview This file contains the Clutz2 output for a simple goog.provide.
4+
* It was manually created and is a support file for the actual test.
5+
*/
6+
7+
declare namespace ಠ_ಠ.clutz {
8+
namespace demo8 {
9+
export class C {
10+
private noStructuralTyping_demo8$C: any;
11+
}
12+
} // namespace demo8
13+
} // ಠ_ಠ.clutz
14+
15+
declare module 'goog:demo8' {
16+
import demo8 = ಠ_ಠ.clutz.demo8;
17+
export default demo8;
18+
}

test_files/clutz_imports.declaration.no_externs/clutz_output_demo1.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.module.
34
* It was manually created and is a support file for the actual test.

test_files/clutz_imports.declaration.no_externs/clutz_output_demo2.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.provide.
34
* It was manually created and is a support file for the actual test.

test_files/clutz_imports.declaration.no_externs/clutz_output_demo3.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.module.
34
* It was manually created and is a support file for the actual test.

test_files/clutz_imports.declaration.no_externs/clutz_output_demo4.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.provide.
34
* It was manually created and is a support file for the actual test.

test_files/clutz_imports.declaration.no_externs/clutz_output_demo5.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.module.
34
* It was manually created and is a support file for the actual test.

test_files/clutz_imports.declaration.no_externs/clutz_output_demo6.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//!! generated by clutz.
12
/**
23
* @fileoverview This file contains the Clutz output for a simple goog.module,
34
* with a generic class.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//!! generated by clutz.
2+
/**
3+
* @fileoverview This file contains the Clutz output for an externs file.
4+
* It was manually created and is a support file for the actual test.
5+
*/
6+
7+
declare namespace demo7 {
8+
class C {
9+
foo(): void;
10+
}
11+
}

0 commit comments

Comments
 (0)