@@ -21,15 +21,19 @@ import * as googmodule from './googmodule';
2121import * as path from './path' ;
2222import { isDeclaredInClutzDts } from './type_translator' ;
2323
24+ interface ClutzHost {
25+ /** See compiler_host.ts */
26+ rootDirsRelative ( fileName : string ) : string ;
27+ }
28+
2429/**
2530 * Constructs a ts.CustomTransformerFactory that postprocesses the .d.ts
2631 * that are generated by ordinary TypeScript compilations to add some
2732 * Clutz-specific logic. See generateClutzAliases.
2833 */
2934export function makeDeclarationTransformerFactory (
3035 typeChecker : ts . TypeChecker ,
31- googmoduleHost : googmodule . GoogModuleProcessorHost ) :
32- ts . CustomTransformerFactory {
36+ host : ClutzHost & googmodule . GoogModuleProcessorHost ) : ts . CustomTransformerFactory {
3337 return ( context : ts . TransformationContext ) : ts . CustomTransformer => {
3438 return {
3539 transformBundle ( ) : ts . Bundle {
@@ -49,8 +53,7 @@ export function makeDeclarationTransformerFactory(
4953 // import 'path/to/the/js_file';
5054 // so to for that import to resolve, you need to first import the clutz
5155 // d.ts that defines that declared module.
52- const imports =
53- gatherNecessaryClutzImports ( googmoduleHost , typeChecker , file ) ;
56+ const imports = gatherNecessaryClutzImports ( host , typeChecker , file ) ;
5457 let importStmts : ts . Statement [ ] | undefined ;
5558 if ( imports . length > 0 ) {
5659 importStmts = imports . map ( fileName => {
@@ -66,22 +69,56 @@ export function makeDeclarationTransformerFactory(
6669 // Construct `declare global {}` in the Clutz namespace for symbols
6770 // Clutz might use.
6871 const globalBlock = generateClutzAliases (
69- file , googmoduleHost . pathToModuleName ( '' , file . fileName ) ,
70- typeChecker , options ) ;
72+ file , host . pathToModuleName ( '' , file . fileName ) , typeChecker ,
73+ options ) ;
7174
7275 // Only need to transform file if we needed one of the above additions.
7376 if ( ! importStmts && ! globalBlock ) return file ;
7477
75- return ts . factory . updateSourceFile ( file , [
76- ...( importStmts ?? [ ] ) ,
77- ...file . statements ,
78- ...( globalBlock ? [ globalBlock ] : [ ] ) ,
79- ] ) ;
78+ return ts . factory . updateSourceFile (
79+ file ,
80+ ts . setTextRange (
81+ ts . factory . createNodeArray ( [
82+ ...( importStmts ?? [ ] ) ,
83+ ...file . statements ,
84+ ...( globalBlock ? [ globalBlock ] : [ ] ) ,
85+ ] ) ,
86+ file . statements ) ,
87+ file . isDeclarationFile ,
88+ file . referencedFiles . map (
89+ f => fixRelativeReference ( f , file , options , host ) ) ,
90+ // /// <reference types="x" /> directives are ignored under bazel.
91+ /*typeReferences=*/ [ ] ) ;
8092 }
8193 } ;
8294 } ;
8395}
8496
97+ /**
98+ * Fixes a relative reference from an output file with respect to multiple
99+ * rootDirs. See https://github.com/Microsoft/TypeScript/issues/8245 for
100+ * details.
101+ */
102+ function fixRelativeReference (
103+ reference : ts . FileReference , origin : ts . SourceFile ,
104+ options : ts . CompilerOptions , host : ClutzHost ) : ts . FileReference {
105+ if ( ! options . outDir || ! options . rootDir ) {
106+ return reference ;
107+ }
108+ const originDir = path . dirname ( origin . fileName ) ;
109+ // Where TypeScript expects the output to be.
110+ const expectedOutDir =
111+ path . join ( options . outDir , path . relative ( options . rootDir , originDir ) ) ;
112+ const referencedFile = path . join ( expectedOutDir , reference . fileName ) ;
113+ // Where the output is actually emitted.
114+ const actualOutDir =
115+ path . join ( options . outDir , host . rootDirsRelative ( originDir ) ) ;
116+ const fixedReference = path . relative ( actualOutDir , referencedFile ) ;
117+
118+ reference . fileName = fixedReference ;
119+ return reference ;
120+ }
121+
85122/** Compares two strings and returns a number suitable for use in sort(). */
86123function stringCompare ( a : string , b : string ) : number {
87124 if ( a < b ) return - 1 ;
0 commit comments