@@ -11,9 +11,7 @@ import type { SourceFile } from './sourceFile';
1111
1212import type { KnownCodec } from './knownImports' ;
1313
14- type ResolvedRef = { type : 'ref' ; name : string ; location : string } ;
15-
16- type ResolvedIdentifier = ResolvedRef | { type : 'codec' ; schema : KnownCodec } ;
14+ type ResolvedIdentifier = Schema | { type : 'codec' ; schema : KnownCodec } ;
1715
1816function codecIdentifier (
1917 project : Project ,
@@ -57,34 +55,99 @@ function codecIdentifier(
5755 if ( object . type !== 'Identifier' ) {
5856 return E . left ( `Unimplemented object type ${ object . type } ` ) ;
5957 }
60- const objectSym = source . symbols . imports . find (
58+
59+ // Parse member expressions that come from `* as foo` imports
60+ const starImportSym = source . symbols . imports . find (
6161 ( s ) => s . localName === object . value && s . type === 'star' ,
6262 ) ;
63- if ( objectSym === undefined ) {
64- return E . left ( `Unknown symbol ${ object . value } ` ) ;
65- } else if ( id . property . type !== 'Identifier' ) {
66- return E . left ( `Unimplemented property type ${ id . property . type } ` ) ;
67- }
63+ if ( starImportSym !== undefined ) {
64+ if ( id . property . type !== 'Identifier' ) {
65+ return E . left ( `Unimplemented property type ${ id . property . type } ` ) ;
66+ }
6867
69- const name = id . property . value ;
70- const knownImport = project . resolveKnownImport ( objectSym . from , name ) ;
71- if ( knownImport !== undefined ) {
72- return E . right ( { type : 'codec' , schema : knownImport } ) ;
73- }
68+ const name = id . property . value ;
69+ const knownImport = project . resolveKnownImport ( starImportSym . from , name ) ;
70+ if ( knownImport !== undefined ) {
71+ return E . right ( { type : 'codec' , schema : knownImport } ) ;
72+ }
73+
74+ if ( ! starImportSym . from . startsWith ( '.' ) ) {
75+ return E . right ( { type : 'ref' , name, location : starImportSym . from } ) ;
76+ }
77+
78+ const newInitE = findSymbolInitializer ( project , source , [
79+ starImportSym . localName ,
80+ name ,
81+ ] ) ;
82+ if ( E . isLeft ( newInitE ) ) {
83+ return newInitE ;
84+ }
7485
75- if ( ! objectSym . from . startsWith ( '.' ) ) {
76- return E . right ( { type : 'ref' , name, location : objectSym . from } ) ;
86+ return E . right ( { type : 'ref' , name, location : newInitE . right [ 0 ] . path } ) ;
7787 }
7888
79- const newInitE = findSymbolInitializer ( project , source , [
80- objectSym . localName ,
81- name ,
82- ] ) ;
83- if ( E . isLeft ( newInitE ) ) {
84- return newInitE ;
89+ // Parse member expressions that come from `import { foo } from 'foo'` imports
90+ const objectImportSym = source . symbols . imports . find (
91+ ( s ) => s . localName === object . value && s . type === 'named' ,
92+ ) ;
93+ if ( objectImportSym !== undefined ) {
94+ if ( id . property . type !== 'Identifier' ) {
95+ return E . left ( `Unimplemented property type ${ id . property . type } ` ) ;
96+ }
97+ const name = id . property . value ;
98+
99+ if ( ! objectImportSym . from . startsWith ( '.' ) ) {
100+ return E . left (
101+ `Unimplemented named member reference '${ objectImportSym . localName } .${ name } ' from '${ objectImportSym . from } '` ,
102+ ) ;
103+ }
104+
105+ const newInitE = findSymbolInitializer ( project , source , [
106+ objectImportSym . localName ,
107+ name ,
108+ ] ) ;
109+ if ( E . isLeft ( newInitE ) ) {
110+ return newInitE ;
111+ }
112+ const [ newSourceFile , newInit ] = newInitE . right ;
113+
114+ const objectSchemaE = parsePlainInitializer ( project , newSourceFile , newInit ) ;
115+ if ( E . isLeft ( objectSchemaE ) ) {
116+ return objectSchemaE ;
117+ } else if ( objectSchemaE . right . type !== 'object' ) {
118+ return E . left ( `Expected object, got '${ objectSchemaE . right . type } '` ) ;
119+ } else if ( objectSchemaE . right . properties [ name ] === undefined ) {
120+ return E . left (
121+ `Unknown property '${ name } ' in '${ objectImportSym . localName } ' from '${ objectImportSym . from } '` ,
122+ ) ;
123+ } else {
124+ return E . right ( objectSchemaE . right . properties [ name ] ! ) ;
125+ }
85126 }
86127
87- return E . right ( { type : 'ref' , name, location : newInitE . right [ 0 ] . path } ) ;
128+ // Parse locally declared member expressions
129+ const declarationSym = source . symbols . declarations . find (
130+ ( s ) => s . name === object . value ,
131+ ) ;
132+ if ( declarationSym === undefined ) {
133+ return E . left ( `Unknown identifier ${ object . value } ` ) ;
134+ } else if ( id . property . type !== 'Identifier' ) {
135+ return E . left ( `Unimplemented property type ${ id . property . type } ` ) ;
136+ }
137+ const schemaE = parsePlainInitializer ( project , source , declarationSym . init ) ;
138+ if ( E . isLeft ( schemaE ) ) {
139+ return schemaE ;
140+ } else if ( schemaE . right . type !== 'object' ) {
141+ return E . left (
142+ `Expected object, got '${ schemaE . right . type } ' for '${ declarationSym . name } '` ,
143+ ) ;
144+ } else if ( schemaE . right . properties [ id . property . value ] === undefined ) {
145+ return E . left (
146+ `Unknown property '${ id . property . value } ' in '${ declarationSym . name } '` ,
147+ ) ;
148+ } else {
149+ return E . right ( schemaE . right . properties [ id . property . value ] ! ) ;
150+ }
88151 } else {
89152 return E . left ( `Unimplemented codec type ${ id } ` ) ;
90153 }
@@ -261,7 +324,7 @@ export function parseCodecInitializer(
261324 }
262325 const identifier = identifierE . right ;
263326
264- if ( identifier . type === 'ref ') {
327+ if ( identifier . type !== 'codec ') {
265328 return E . right ( identifier ) ;
266329 }
267330
@@ -278,7 +341,7 @@ export function parseCodecInitializer(
278341 }
279342 const identifier = identifierE . right ;
280343
281- if ( identifier . type === 'ref ') {
344+ if ( identifier . type !== 'codec ') {
282345 return E . right ( identifier ) ;
283346 }
284347
0 commit comments