@@ -114,45 +114,104 @@ class Transformer {
114114 }
115115
116116 // import ... from 'lit-localize' -> (removed)
117- if ( this . isLitLocalizeImport ( node ) ) {
118- return undefined ;
117+ if ( ts . isImportDeclaration ( node ) ) {
118+ const moduleSymbol = this . typeChecker . getSymbolAtLocation (
119+ node . moduleSpecifier
120+ ) ;
121+ if ( moduleSymbol && this . isLitLocalizeModule ( moduleSymbol ) ) {
122+ return undefined ;
123+ }
119124 }
120125
121- // configureTransformLocalization(...) -> {getLocale: () => "es-419"}
122- if (
123- this . isCallToTaggedFunction (
124- node ,
125- '_LIT_LOCALIZE_CONFIGURE_TRANSFORM_LOCALIZATION_'
126- )
127- ) {
128- return ts . createObjectLiteral (
129- [
130- ts . createPropertyAssignment (
131- ts . createIdentifier ( 'getLocale' ) ,
132- ts . createArrowFunction (
133- undefined ,
134- undefined ,
135- [ ] ,
136- undefined ,
137- ts . createToken ( ts . SyntaxKind . EqualsGreaterThanToken ) ,
138- ts . createStringLiteral ( this . locale )
139- )
140- ) ,
141- ] ,
142- false
143- ) ;
126+ if ( ts . isCallExpression ( node ) ) {
127+ // configureTransformLocalization(...) -> {getLocale: () => "es-419"}
128+ if (
129+ this . typeHasProperty (
130+ node . expression ,
131+ '_LIT_LOCALIZE_CONFIGURE_TRANSFORM_LOCALIZATION_'
132+ )
133+ ) {
134+ return ts . createObjectLiteral (
135+ [
136+ ts . createPropertyAssignment (
137+ ts . createIdentifier ( 'getLocale' ) ,
138+ ts . createArrowFunction (
139+ undefined ,
140+ undefined ,
141+ [ ] ,
142+ undefined ,
143+ ts . createToken ( ts . SyntaxKind . EqualsGreaterThanToken ) ,
144+ ts . createStringLiteral ( this . locale )
145+ )
146+ ) ,
147+ ] ,
148+ false
149+ ) ;
150+ }
151+
152+ // configureLocalization(...) -> Error
153+ if (
154+ this . typeHasProperty (
155+ node . expression ,
156+ '_LIT_LOCALIZE_CONFIGURE_LOCALIZATION_'
157+ )
158+ ) {
159+ // TODO(aomarks) This error is not surfaced earlier in the analysis phase
160+ // as a nicely formatted diagnostic, but it should be.
161+ throw new KnownError (
162+ 'Cannot use configureLocalization in transform mode. ' +
163+ 'Use configureTransformLocalization instead.'
164+ ) ;
165+ }
166+
167+ // Localized(LitElement) -> LitElement
168+ if ( this . typeHasProperty ( node . expression , '_LIT_LOCALIZE_LOCALIZED_' ) ) {
169+ if ( node . arguments . length !== 1 ) {
170+ // TODO(aomarks) Surface as diagnostic instead.
171+ throw new KnownError (
172+ `Expected Localized mixin call to have one argument, ` +
173+ `got ${ node . arguments . length } `
174+ ) ;
175+ }
176+ return node . arguments [ 0 ] ;
177+ }
144178 }
145179
146- // configureLocalization(...) -> Error
147- if (
148- this . isCallToTaggedFunction ( node , '_LIT_LOCALIZE_CONFIGURE_LOCALIZATION_' )
149- ) {
150- // TODO(aomarks) This error is not surfaced earlier in the analysis phase
151- // as a nicely formatted diagnostic, but it should be.
152- throw new KnownError (
153- 'Cannot use configureLocalization in transform mode. ' +
154- 'Use configureTransformLocalization instead.'
155- ) ;
180+ // LOCALE_STATUS_EVENT -> "lit-localize-status"
181+ //
182+ // We want to replace this imported string constant with its static value so
183+ // that we can always safely remove the 'lit-localize' module import.
184+ //
185+ // TODO(aomarks) Maybe we should error here instead, since lit-localize
186+ // won't fire any of these events in transform mode? But I'm still thinking
187+ // about the use case of an app that can run in either runtime or transform
188+ // mode without code changes (e.g. runtime for dev, transform for
189+ // production)...
190+ //
191+ // We can't tag this string const with a special property like we do with
192+ // our exported functions, because doing so breaks lookups into
193+ // `WindowEventMap`. So we instead identify the symbol by name, and check
194+ // that it was declared in the lit-localize module.
195+ let eventSymbol = this . typeChecker . getSymbolAtLocation ( node ) ;
196+ if ( eventSymbol && eventSymbol . name === 'LOCALE_STATUS_EVENT' ) {
197+ if ( eventSymbol . flags & ts . SymbolFlags . Alias ) {
198+ // Symbols will be aliased in the case of
199+ // `import {LOCALE_STATUS_EVENT} ...`
200+ // but not in the case of `import * as ...`.
201+ eventSymbol = this . typeChecker . getAliasedSymbol ( eventSymbol ) ;
202+ }
203+ for ( const decl of eventSymbol . declarations ) {
204+ let sourceFile : ts . Node = decl ;
205+ while ( ! ts . isSourceFile ( sourceFile ) ) {
206+ sourceFile = sourceFile . parent ;
207+ }
208+ const sourceFileSymbol = this . typeChecker . getSymbolAtLocation (
209+ sourceFile
210+ ) ;
211+ if ( sourceFileSymbol && this . isLitLocalizeModule ( sourceFileSymbol ) ) {
212+ return ts . createStringLiteral ( 'lit-localize-status' ) ;
213+ }
214+ }
156215 }
157216
158217 return ts . visitEachChild ( node , this . boundVisitNode , this . context ) ;
@@ -380,16 +439,11 @@ class Transformer {
380439 }
381440
382441 /**
383- * Return whether the given node is an import for the lit-localize module.
442+ * Return whether the given symbol looks like one of the lit-localize modules
443+ * (because it exports one of the special tagged functions).
384444 */
385- isLitLocalizeImport ( node : ts . Node ) : node is ts . ImportDeclaration {
386- if ( ! ts . isImportDeclaration ( node ) ) {
387- return false ;
388- }
389- const moduleSymbol = this . typeChecker . getSymbolAtLocation (
390- node . moduleSpecifier
391- ) ;
392- if ( ! moduleSymbol || ! moduleSymbol . exports ) {
445+ isLitLocalizeModule ( moduleSymbol : ts . Symbol ) : boolean {
446+ if ( ! moduleSymbol . exports ) {
393447 return false ;
394448 }
395449 const exports = moduleSymbol . exports . values ( ) ;
@@ -398,27 +452,30 @@ class Transformer {
398452 } ) {
399453 const type = this . typeChecker . getTypeAtLocation ( xport . valueDeclaration ) ;
400454 const props = this . typeChecker . getPropertiesOfType ( type ) ;
401- if ( props . some ( ( prop ) => prop . escapedName === '_LIT_LOCALIZE_MSG_' ) ) {
455+ if (
456+ props . some (
457+ ( prop ) =>
458+ prop . escapedName === '_LIT_LOCALIZE_MSG_' ||
459+ prop . escapedName === '_LIT_LOCALIZE_LOCALIZED_'
460+ )
461+ ) {
402462 return true ;
403463 }
404464 }
405465 return false ;
406466 }
407467
408468 /**
409- * Return whether the given node is call to a function which is is "tagged"
410- * with the given special identifying property (e.g. "_LIT_LOCALIZE_MSG_").
469+ * Return whether the tpe of the given node is "tagged" with the given special
470+ * identifying property (e.g. "_LIT_LOCALIZE_MSG_").
411471 */
412- isCallToTaggedFunction (
472+ typeHasProperty (
413473 node : ts . Node ,
414- tagProperty : string
474+ propertyName : string
415475 ) : node is ts . CallExpression {
416- if ( ! ts . isCallExpression ( node ) ) {
417- return false ;
418- }
419- const type = this . typeChecker . getTypeAtLocation ( node . expression ) ;
476+ const type = this . typeChecker . getTypeAtLocation ( node ) ;
420477 const props = this . typeChecker . getPropertiesOfType ( type ) ;
421- return props . some ( ( prop ) => prop . escapedName === tagProperty ) ;
478+ return props . some ( ( prop ) => prop . escapedName === propertyName ) ;
422479 }
423480}
424481
0 commit comments