@@ -19,6 +19,7 @@ import templateBuilder from '@babel/template';
1919import { createHash } from 'crypto' ;
2020import * as fs from 'fs' ;
2121import * as path from 'path' ;
22+ import { lt as semverLt } from 'semver' ;
2223import { RawSourceMap , SourceMapConsumer , SourceMapGenerator } from 'source-map' ;
2324import { minify } from 'terser' ;
2425import * as v8 from 'v8' ;
@@ -32,6 +33,8 @@ import {
3233import { allowMangle , allowMinify , shouldBeautify } from './environment-options' ;
3334import { I18nOptions } from './i18n-options' ;
3435
36+ type LocalizeUtilities = typeof import ( '@angular/localize/src/tools/src/source_file_utils' ) ;
37+
3538const cacache = require ( 'cacache' ) ;
3639const deserialize = ( ( v8 as unknown ) as { deserialize ( buffer : Buffer ) : unknown } ) . deserialize ;
3740
@@ -547,7 +550,6 @@ export async function createI18nPlugins(
547550 localeDataContent ?: string ,
548551) {
549552 const plugins = [ ] ;
550- // tslint:disable-next-line: no-implicit-dependencies
551553 const localizeDiag = await import ( '@angular/localize/src/tools/src/diagnostics' ) ;
552554
553555 const diagnostics = new localizeDiag . Diagnostics ( ) ;
@@ -723,9 +725,7 @@ async function inlineLocalesDirect(ast: ParseResult, options: InlineOptions) {
723725
724726 const { default : generate } = await import ( '@babel/generator' ) ;
725727
726- // tslint:disable-next-line: no-implicit-dependencies
727728 const utils = await import ( '@angular/localize/src/tools/src/source_file_utils' ) ;
728- // tslint:disable-next-line: no-implicit-dependencies
729729 const localizeDiag = await import ( '@angular/localize/src/tools/src/diagnostics' ) ;
730730
731731 const diagnostics = new localizeDiag . Diagnostics ( ) ;
@@ -829,21 +829,24 @@ function inlineCopyOnly(options: InlineOptions) {
829829function findLocalizePositions (
830830 ast : ParseResult ,
831831 options : InlineOptions ,
832- // tslint:disable-next-line: no-implicit-dependencies
833- utils : typeof import ( '@angular/localize/src/tools/src/source_file_utils' ) ,
832+ utils : LocalizeUtilities ,
834833) : LocalizePosition [ ] {
835834 const positions : LocalizePosition [ ] = [ ] ;
835+
836+ // Workaround to ensure a path hub is present for traversal
837+ const { File } = require ( '@babel/core' ) ;
838+ const file = new File ( { } , { code : options . code , ast } ) ;
839+
836840 if ( options . es5 ) {
837- traverse ( ast , {
838- CallExpression ( path : NodePath < types . CallExpression > ) {
841+ traverse ( file . ast , {
842+ CallExpression ( path ) {
839843 const callee = path . get ( 'callee' ) ;
840844 if (
841845 callee . isIdentifier ( ) &&
842846 callee . node . name === localizeName &&
843847 utils . isGlobalIdentifier ( callee )
844848 ) {
845- const messageParts = utils . unwrapMessagePartsFromLocalizeCall ( path ) ;
846- const expressions = utils . unwrapSubstitutionsFromLocalizeCall ( path . node ) ;
849+ const [ messageParts , expressions ] = unwrapLocalizeCall ( path , utils ) ;
847850 positions . push ( {
848851 // tslint:disable-next-line: no-non-null-assertion
849852 start : path . node . start ! ,
@@ -856,32 +859,80 @@ function findLocalizePositions(
856859 } ,
857860 } ) ;
858861 } else {
859- const traverseFast = ( ( types as unknown ) as {
860- traverseFast : ( node : types . Node , enter : ( node : types . Node ) => void ) => void ;
861- } ) . traverseFast ;
862-
863- traverseFast ( ast , node => {
864- if (
865- node . type === 'TaggedTemplateExpression' &&
866- types . isIdentifier ( node . tag ) &&
867- node . tag . name === localizeName
868- ) {
869- const messageParts = utils . unwrapMessagePartsFromTemplateLiteral ( node . quasi . quasis ) ;
870- positions . push ( {
871- // tslint:disable-next-line: no-non-null-assertion
872- start : node . start ! ,
873- // tslint:disable-next-line: no-non-null-assertion
874- end : node . end ! ,
875- messageParts,
876- expressions : node . quasi . expressions ,
877- } ) ;
878- }
862+ traverse ( file . ast , {
863+ TaggedTemplateExpression ( path ) {
864+ if ( types . isIdentifier ( path . node . tag ) && path . node . tag . name === localizeName ) {
865+ const [ messageParts , expressions ] = unwrapTemplateLiteral ( path , utils ) ;
866+ positions . push ( {
867+ // tslint:disable-next-line: no-non-null-assertion
868+ start : path . node . start ! ,
869+ // tslint:disable-next-line: no-non-null-assertion
870+ end : path . node . end ! ,
871+ messageParts,
872+ expressions,
873+ } ) ;
874+ }
875+ } ,
879876 } ) ;
880877 }
881878
882879 return positions ;
883880}
884881
882+ // TODO: Remove this for v11.
883+ // This check allows the CLI to support both FW 10.0 and 10.1
884+ let localizeOld : boolean | undefined ;
885+
886+ function unwrapTemplateLiteral (
887+ path : NodePath < types . TemplateLiteral > ,
888+ utils : LocalizeUtilities ,
889+ ) : [ TemplateStringsArray , types . Expression [ ] ] {
890+ if ( localizeOld === undefined ) {
891+ const { version : localizeVersion } = require ( '@angular/localize/package.json' ) ;
892+ localizeOld = semverLt ( localizeVersion , '10.1.0-rc.0' , { includePrerelease : true } ) ;
893+ }
894+
895+ if ( localizeOld ) {
896+ // tslint:disable-next-line: no-any
897+ const messageParts = utils . unwrapMessagePartsFromTemplateLiteral ( path . node . quasi . quasis as any ) ;
898+
899+ return [ ( messageParts as unknown ) as TemplateStringsArray , path . node . quasi . expressions ] ;
900+ }
901+
902+ const [ messageParts ] = utils . unwrapMessagePartsFromTemplateLiteral (
903+ path . get ( 'quasi' ) . get ( 'quasis' ) ,
904+ ) ;
905+ const [ expressions ] = utils . unwrapExpressionsFromTemplateLiteral ( path . get ( 'quasi' ) ) ;
906+
907+ return [ messageParts , expressions ] ;
908+ }
909+
910+ function unwrapLocalizeCall (
911+ path : NodePath < types . CallExpression > ,
912+ utils : LocalizeUtilities ,
913+ ) : [ TemplateStringsArray , types . Expression [ ] ] {
914+ if ( localizeOld === undefined ) {
915+ const { version : localizeVersion } = require ( '@angular/localize/package.json' ) ;
916+ localizeOld = semverLt ( localizeVersion , '10.1.0-rc.0' , { includePrerelease : true } ) ;
917+ }
918+
919+ if ( localizeOld ) {
920+ const messageParts = utils . unwrapMessagePartsFromLocalizeCall ( path ) ;
921+ // tslint:disable-next-line: no-any
922+ const expressions = utils . unwrapSubstitutionsFromLocalizeCall ( path . node as any ) ;
923+
924+ return [
925+ ( messageParts as unknown ) as TemplateStringsArray ,
926+ ( expressions as unknown ) as types . Expression [ ] ,
927+ ] ;
928+ }
929+
930+ const [ messageParts ] = utils . unwrapMessagePartsFromLocalizeCall ( path ) ;
931+ const [ expressions ] = utils . unwrapSubstitutionsFromLocalizeCall ( path ) ;
932+
933+ return [ messageParts , expressions ] ;
934+ }
935+
885936async function loadLocaleData ( path : string , optimize : boolean , es5 : boolean ) : Promise < string > {
886937 // The path is validated during option processing before the build starts
887938 const content = fs . readFileSync ( path , 'utf8' ) ;
0 commit comments