@@ -113,19 +113,17 @@ export function runOneBuild(args: string[], inputs?: {[path: string]: string}):
113
113
}
114
114
}
115
115
116
- const expectedOuts = config [ 'angularCompilerOptions' ] [ 'expectedOut' ] ;
116
+ // These are options passed through from the `ng_module` rule which aren't supported
117
+ // by the `@angular/compiler-cli` and are only intended for `ngc-wrapped`.
118
+ const { expectedOut, _useManifestPathsAsModuleName} = config [ 'angularCompilerOptions' ] ;
117
119
118
120
const { basePath} = ng . calcProjectFileAndBasePath ( project ) ;
119
121
const compilerOpts = ng . createNgCompilerOptions ( basePath , config , tsOptions ) ;
120
122
const tsHost = ts . createCompilerHost ( compilerOpts , true ) ;
121
123
const { diagnostics} = compile ( {
122
124
allDepsCompiledWithBazel : ALL_DEPS_COMPILED_WITH_BAZEL ,
123
- compilerOpts,
124
- tsHost,
125
- bazelOpts,
126
- files,
127
- inputs,
128
- expectedOuts
125
+ useManifestPathsAsModuleName : _useManifestPathsAsModuleName ,
126
+ expectedOuts : expectedOut , compilerOpts, tsHost, bazelOpts, files, inputs,
129
127
} ) ;
130
128
if ( diagnostics . length ) {
131
129
console . error ( ng . formatDiagnostics ( diagnostics ) ) ;
@@ -144,9 +142,11 @@ export function relativeToRootDirs(filePath: string, rootDirs: string[]): string
144
142
return filePath ;
145
143
}
146
144
147
- export function compile ( { allDepsCompiledWithBazel = true , compilerOpts, tsHost, bazelOpts, files,
148
- inputs, expectedOuts, gatherDiagnostics, bazelHost} : {
145
+ export function compile ( { allDepsCompiledWithBazel = true , useManifestPathsAsModuleName,
146
+ compilerOpts, tsHost, bazelOpts, files, inputs, expectedOuts,
147
+ gatherDiagnostics, bazelHost} : {
149
148
allDepsCompiledWithBazel ?: boolean ,
149
+ useManifestPathsAsModuleName ?: boolean ,
150
150
compilerOpts : ng . CompilerOptions ,
151
151
tsHost : ts . CompilerHost , inputs ?: { [ path : string ] : string } ,
152
152
bazelOpts : BazelOptions ,
@@ -199,13 +199,14 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost,
199
199
throw new Error ( `Couldn't find bazel bin in the rootDirs: ${ compilerOpts . rootDirs } ` ) ;
200
200
}
201
201
202
- const expectedOutsSet = new Set ( expectedOuts . map ( p => p . replace ( / \\ / g , '/' ) ) ) ;
202
+ const expectedOutsSet = new Set ( expectedOuts . map ( p => convertToForwardSlashPath ( p ) ) ) ;
203
203
204
204
const originalWriteFile = tsHost . writeFile . bind ( tsHost ) ;
205
205
tsHost . writeFile =
206
206
( fileName : string , content : string , writeByteOrderMark : boolean ,
207
207
onError ?: ( message : string ) => void , sourceFiles ?: ts . SourceFile [ ] ) => {
208
- const relative = relativeToRootDirs ( fileName . replace ( / \\ / g, '/' ) , [ compilerOpts . rootDir ] ) ;
208
+ const relative =
209
+ relativeToRootDirs ( convertToForwardSlashPath ( fileName ) , [ compilerOpts . rootDir ] ) ;
209
210
if ( expectedOutsSet . has ( relative ) ) {
210
211
expectedOutsSet . delete ( relative ) ;
211
212
originalWriteFile ( fileName , content , writeByteOrderMark , onError , sourceFiles ) ;
@@ -290,20 +291,32 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost,
290
291
291
292
const ngHost = ng . createCompilerHost ( { options : compilerOpts , tsHost : bazelHost } ) ;
292
293
const fileNameToModuleNameCache = new Map < string , string > ( ) ;
293
- ngHost . fileNameToModuleName = ( importedFilePath : string , containingFilePath : string ) => {
294
+ ngHost . fileNameToModuleName = ( importedFilePath : string , containingFilePath ?: string ) => {
295
+ const cacheKey = `${ importedFilePath } :${ containingFilePath } ` ;
294
296
// Memoize this lookup to avoid expensive re-parses of the same file
295
297
// When run as a worker, the actual ts.SourceFile is cached
296
298
// but when we don't run as a worker, there is no cache.
297
299
// For one example target in g3, we saw a cache hit rate of 7590/7695
298
- if ( fileNameToModuleNameCache . has ( importedFilePath ) ) {
299
- return fileNameToModuleNameCache . get ( importedFilePath ) ;
300
+ if ( fileNameToModuleNameCache . has ( cacheKey ) ) {
301
+ return fileNameToModuleNameCache . get ( cacheKey ) ;
300
302
}
301
- const result = doFileNameToModuleName ( importedFilePath ) ;
302
- fileNameToModuleNameCache . set ( importedFilePath , result ) ;
303
+ const result = doFileNameToModuleName ( importedFilePath , containingFilePath ) ;
304
+ fileNameToModuleNameCache . set ( cacheKey , result ) ;
303
305
return result ;
304
306
} ;
305
307
306
- function doFileNameToModuleName ( importedFilePath : string ) : string {
308
+ function doFileNameToModuleName ( importedFilePath : string , containingFilePath ?: string ) : string {
309
+ const relativeTargetPath =
310
+ relativeToRootDirs ( importedFilePath , compilerOpts . rootDirs ) . replace ( EXT , '' ) ;
311
+ const manifestTargetPath = `${ bazelOpts . workspaceName } /${ relativeTargetPath } ` ;
312
+ if ( useManifestPathsAsModuleName === true ) {
313
+ return manifestTargetPath ;
314
+ }
315
+
316
+ // Unless manifest paths are explicitly enforced, we initially check if a module name is
317
+ // set for the given source file. The compiler host from `@bazel/typescript` sets source
318
+ // file module names if the compilation targets either UMD or AMD. To ensure that the AMD
319
+ // module names match, we first consider those.
307
320
try {
308
321
const sourceFile = ngHost . getSourceFile ( importedFilePath , ts . ScriptTarget . Latest ) ;
309
322
if ( sourceFile && sourceFile . moduleName ) {
@@ -342,11 +355,31 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost,
342
355
ngHost . amdModuleName ) {
343
356
return ngHost . amdModuleName ( { fileName : importedFilePath } as ts . SourceFile ) ;
344
357
}
345
- const result = relativeToRootDirs ( importedFilePath , compilerOpts . rootDirs ) . replace ( EXT , '' ) ;
346
- if ( result . startsWith ( NODE_MODULES ) ) {
347
- return result . substr ( NODE_MODULES . length ) ;
358
+
359
+ // If no AMD module name has been set for the source file by the `@bazel/typescript` compiler
360
+ // host, and the target file is not part of a flat module node module package, we use the
361
+ // following rules (in order):
362
+ // 1. If target file is part of `node_modules/`, we use the package module name.
363
+ // 2. If no containing file is specified, or the target file is part of a different
364
+ // compilation unit, we use a Bazel manifest path. Relative paths are not possible
365
+ // since we don't have a containing file, and the target file could be located in the
366
+ // output directory, or in an external Bazel repository.
367
+ // 3. If both rules above didn't match, we compute a relative path between the source files
368
+ // since they are part of the same compilation unit.
369
+ // Note that we don't want to always use (2) because it could mean that compilation outputs
370
+ // are always leaking Bazel-specific paths, and the output is not self-contained. This could
371
+ // break `esm2015` or `esm5` output for Angular package release output
372
+ // Omit the `node_modules` prefix if the module name of an NPM package is requested.
373
+ if ( relativeTargetPath . startsWith ( NODE_MODULES ) ) {
374
+ return relativeTargetPath . substr ( NODE_MODULES . length ) ;
375
+ } else if (
376
+ containingFilePath == null || ! bazelOpts . compilationTargetSrc . includes ( importedFilePath ) ) {
377
+ return manifestTargetPath ;
348
378
}
349
- return bazelOpts . workspaceName + '/' + result ;
379
+ const containingFileDir =
380
+ path . dirname ( relativeToRootDirs ( containingFilePath , compilerOpts . rootDirs ) ) ;
381
+ const relativeImportPath = path . posix . relative ( containingFileDir , relativeTargetPath ) ;
382
+ return relativeImportPath . startsWith ( '.' ) ? relativeImportPath : `./${ relativeImportPath } ` ;
350
383
}
351
384
352
385
ngHost . toSummaryFileName = ( fileName : string , referringSrcFileName : string ) => path . posix . join (
@@ -464,6 +497,10 @@ function isCompilationTarget(bazelOpts: BazelOptions, sf: ts.SourceFile): boolea
464
497
( bazelOpts . compilationTargetSrc . indexOf ( sf . fileName ) !== - 1 ) ;
465
498
}
466
499
500
+ function convertToForwardSlashPath ( filePath : string ) : string {
501
+ return filePath . replace ( / \\ / g, '/' ) ;
502
+ }
503
+
467
504
function gatherDiagnosticsForInputsOnly (
468
505
options : ng . CompilerOptions , bazelOpts : BazelOptions ,
469
506
ngProgram : ng . Program ) : ( ng . Diagnostic | ts . Diagnostic ) [ ] {
0 commit comments