@@ -12,6 +12,7 @@ import * as path from 'path';
1212import { RawSourceMap , SourceMapConsumer , SourceMapGenerator } from 'source-map' ;
1313import { minify } from 'terser' ;
1414import * as v8 from 'v8' ;
15+ import { SourceMapSource } from 'webpack-sources' ;
1516import { I18nOptions } from './i18n-options' ;
1617import { manglingDisabled } from './mangle-options' ;
1718
@@ -131,7 +132,7 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
131132 downlevelCode = transformResult . code ;
132133
133134 if ( manualSourceMaps && sourceMap && transformResult . map ) {
134- downlevelMap = await mergeSourcemaps ( sourceMap , transformResult . map ) ;
135+ downlevelMap = await mergeSourceMapsFast ( sourceMap , transformResult . map ) ;
135136 } else {
136137 // undefined is needed here to normalize the property type
137138 downlevelMap = transformResult . map || undefined ;
@@ -196,7 +197,28 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
196197 return result ;
197198}
198199
199- async function mergeSourcemaps ( first : RawSourceMap , second : RawSourceMap ) {
200+ function mergeSourceMaps (
201+ inputCode : string ,
202+ inputSourceMap : RawSourceMap ,
203+ resultCode : string ,
204+ resultSourceMap : RawSourceMap ,
205+ filename : string ,
206+ ) : RawSourceMap {
207+ // More accurate but significantly more costly
208+
209+ // The last argument is not yet in the typings
210+ // tslint:disable-next-line: no-any
211+ return new ( SourceMapSource as any ) (
212+ resultCode ,
213+ filename ,
214+ resultSourceMap ,
215+ inputCode ,
216+ inputSourceMap ,
217+ true ,
218+ ) . map ( ) ;
219+ }
220+
221+ async function mergeSourceMapsFast ( first : RawSourceMap , second : RawSourceMap ) {
200222 const sourceRoot = first . sourceRoot ;
201223 const generator = new SourceMapGenerator ( ) ;
202224
@@ -446,6 +468,7 @@ async function processRuntime(
446468export interface InlineOptions {
447469 filename : string ;
448470 code : string ;
471+ map ?: string ;
449472 es5 : boolean ;
450473 outputPath : string ;
451474 missingTranslation ?: 'warning' | 'error' | 'ignore' ;
@@ -469,14 +492,7 @@ export async function inlineLocales(options: InlineOptions) {
469492 }
470493
471494 if ( ! options . code . includes ( localizeName ) ) {
472- for ( const locale of i18n . inlineLocales ) {
473- fs . writeFileSync (
474- path . join ( options . outputPath , i18n . flatOutput ? '' : locale , options . filename ) ,
475- options . code ,
476- ) ;
477- }
478-
479- return { file : options . filename , diagnostics : [ ] , count : 0 } ;
495+ return inlineCopyOnly ( options ) ;
480496 }
481497
482498 const { default : MagicString } = await import ( 'magic-string' ) ;
@@ -490,7 +506,12 @@ export async function inlineLocales(options: InlineOptions) {
490506 const diagnostics = new localizeDiag . Diagnostics ( ) ;
491507
492508 const positions = findLocalizePositions ( options , utils ) ;
509+ if ( positions . length === 0 ) {
510+ return inlineCopyOnly ( options ) ;
511+ }
512+
493513 const content = new MagicString ( options . code ) ;
514+ const inputMap = options . map && JSON . parse ( options . map ) as RawSourceMap ;
494515
495516 for ( const locale of i18n . inlineLocales ) {
496517 const isSourceLocale = locale === i18n . sourceLocale ;
@@ -512,15 +533,46 @@ export async function inlineLocales(options: InlineOptions) {
512533 }
513534
514535 const output = content . toString ( ) ;
515- fs . writeFileSync (
516- path . join ( options . outputPath , i18n . flatOutput ? '' : locale , options . filename ) ,
517- output ,
536+ const outputPath = path . join (
537+ options . outputPath ,
538+ i18n . flatOutput ? '' : locale ,
539+ options . filename ,
518540 ) ;
541+ fs . writeFileSync ( outputPath , output ) ;
542+
543+ if ( inputMap ) {
544+ const contentMap = content . generateMap ( ) ;
545+ const outputMap = mergeSourceMaps (
546+ options . code ,
547+ inputMap ,
548+ output ,
549+ contentMap ,
550+ options . filename ,
551+ ) ;
552+
553+ fs . writeFileSync ( outputPath + '.map' , JSON . stringify ( outputMap ) ) ;
554+ }
519555 }
520556
521557 return { file : options . filename , diagnostics : diagnostics . messages , count : positions . length } ;
522558}
523559
560+ function inlineCopyOnly ( options : InlineOptions ) {
561+ if ( ! i18n ) {
562+ throw new Error ( 'i18n options are missing' ) ;
563+ }
564+
565+ for ( const locale of i18n . inlineLocales ) {
566+ const outputPath = path . join ( options . outputPath , i18n . flatOutput ? '' : locale , options . filename ) ;
567+ fs . writeFileSync ( outputPath , options . code ) ;
568+ if ( options . map ) {
569+ fs . writeFileSync ( outputPath + '.map' , options . map ) ;
570+ }
571+ }
572+
573+ return { file : options . filename , diagnostics : [ ] , count : 0 } ;
574+ }
575+
524576function findLocalizePositions (
525577 options : InlineOptions ,
526578 utils : typeof import ( '@angular/localize/src/tools/src/translate/source_files/source_file_utils' ) ,
@@ -536,10 +588,7 @@ function findLocalizePositions(
536588 traverse ( ast , {
537589 CallExpression ( path : NodePath < types . CallExpression > ) {
538590 const callee = path . get ( 'callee' ) ;
539- if (
540- callee . isIdentifier ( ) &&
541- callee . node . name === localizeName
542- ) {
591+ if ( callee . isIdentifier ( ) && callee . node . name === localizeName ) {
543592 const messageParts = utils . unwrapMessagePartsFromLocalizeCall ( path ) ;
544593 const expressions = utils . unwrapSubstitutionsFromLocalizeCall ( path . node ) ;
545594 positions . push ( {
0 commit comments