@@ -13,6 +13,7 @@ import type {
13
13
ArrayTypeNode ,
14
14
ArrowFunction ,
15
15
Bundle ,
16
+ CallExpression ,
16
17
CallSignatureDeclaration ,
17
18
ClassDeclaration ,
18
19
ClassElement ,
@@ -56,7 +57,7 @@ import type {
56
57
QualifiedName ,
57
58
RestTypeNode ,
58
59
SignatureDeclaration ,
59
- Statement ,
60
+ Statement , StringLiteral ,
60
61
TemplateLiteralTypeNode ,
61
62
TransformationContext ,
62
63
TupleTypeNode ,
@@ -70,7 +71,7 @@ import type {
70
71
TypeReferenceNode ,
71
72
UnionTypeNode ,
72
73
} from 'typescript' ;
73
- import ts from 'typescript' ;
74
+ import ts , { ResolvedModule } from 'typescript' ;
74
75
75
76
import {
76
77
ensureImportIsEmitted ,
@@ -85,6 +86,7 @@ import {
85
86
isNodeWithLocals ,
86
87
NodeConverter ,
87
88
PackExpression ,
89
+ SerializedEntityNameAsExpression ,
88
90
serializeEntityNameAsExpression ,
89
91
} from './reflection-ast.js' ;
90
92
import { SourceFile } from './ts-types.js' ;
@@ -511,23 +513,6 @@ export interface ReflectionTransformerConfig {
511
513
deepkitTypeCompilerOptions ?: DeepkitTypeCompilerOptions ;
512
514
}
513
515
514
- export interface EmbedDeclaration {
515
- name : EntityName ,
516
- sourceFile : SourceFile ,
517
- assignType ?: boolean ;
518
- }
519
-
520
- export class EmbedDeclarations extends Map < Node , EmbedDeclaration > {
521
- getByName ( name : string ) : EmbedDeclaration | null {
522
- for ( const [ , d ] of this ) {
523
- if ( getEntityName ( d . name ) === name ) {
524
- return d ;
525
- }
526
- }
527
- return null ;
528
- }
529
- }
530
-
531
516
/**
532
517
* Read the TypeScript AST and generate pack struct (instructions + pre-defined stack).
533
518
*
@@ -564,7 +549,7 @@ export class ReflectionTransformer implements CustomTransformer {
564
549
* Types added to this map will get a type program at the top root level of the program.
565
550
* This is for imported types, which need to be inlined into the current file, as we do not emit type imports (TS will omit them).
566
551
*/
567
- public embedDeclarations = new EmbedDeclarations ( ) ;
552
+ protected embedDeclarations = new Map < Node , { name : EntityName , sourceFile : SourceFile } > ( ) ;
568
553
569
554
/**
570
555
* When a node was embedded or compiled (from the maps above), we store it here to know to not add it again.
@@ -594,7 +579,7 @@ export class ReflectionTransformer implements CustomTransformer {
594
579
protected context : TransformationContext ,
595
580
) {
596
581
this . f = context . factory ;
597
- this . nodeConverter = new NodeConverter ( this . f , this ) ;
582
+ this . nodeConverter = new NodeConverter ( this . f ) ;
598
583
//it is important to not have undefined values like {paths: undefined} because it would override the read tsconfig.json
599
584
this . compilerOptions = filterUndefined ( context . getCompilerOptions ( ) ) ;
600
585
this . host = createCompilerHost ( this . compilerOptions ) ;
@@ -1819,14 +1804,13 @@ export class ReflectionTransformer implements CustomTransformer {
1819
1804
// this.addImports.push({ identifier: narrowed.exprName, from: originImportStatement.moduleSpecifier });
1820
1805
// }
1821
1806
// }
1807
+ let expression : SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression ( this . f , narrowed . exprName ) ;
1822
1808
if ( isIdentifier ( narrowed . exprName ) ) {
1823
1809
const resolved = this . resolveDeclaration ( narrowed . exprName ) ;
1824
1810
if ( resolved && findSourceFile ( resolved . declaration ) !== this . sourceFile && resolved . importDeclaration ) {
1825
- this . resolveImport ( resolved . declaration , resolved . importDeclaration , narrowed . exprName , program ) ;
1811
+ expression = this . resolveImport ( resolved . declaration , resolved . importDeclaration , narrowed . exprName , expression , program ) ;
1826
1812
}
1827
1813
}
1828
-
1829
- const expression = serializeEntityNameAsExpression ( this . f , narrowed . exprName ) ;
1830
1814
program . pushOp ( ReflectionOp . typeof , program . pushStack ( this . f . createArrowFunction ( undefined , undefined , [ ] , undefined , undefined , expression ) ) ) ;
1831
1815
break ;
1832
1816
}
@@ -1935,11 +1919,12 @@ export class ReflectionTransformer implements CustomTransformer {
1935
1919
* This is a custom resolver based on populated `locals` from the binder. It uses a custom resolution algorithm since
1936
1920
* we have no access to the binder/TypeChecker directly and instantiating a TypeChecker per file/transformer is incredible slow.
1937
1921
*/
1938
- protected resolveDeclaration ( typeName : EntityName ) : { declaration : Node , importDeclaration ?: ImportDeclaration , typeOnly ? : boolean } | void {
1939
- let current : Node = typeName . parent ;
1922
+ protected resolveDeclaration ( typeName : EntityName ) : { declaration : Node , importDeclaration ?: ImportDeclaration , sourceFile : SourceFile , typeOnly : boolean } | void {
1923
+ let current : Node = typeName . parent
1940
1924
if ( typeName . kind === SyntaxKind . QualifiedName ) return ; //namespace access not supported yet, e.g. type a = Namespace.X;
1941
1925
1942
1926
let declaration : Node | undefined = undefined ;
1927
+ let sourceFile : SourceFile = this . sourceFile ;
1943
1928
1944
1929
while ( current ) {
1945
1930
if ( isNodeWithLocals ( current ) && current . locals ) {
@@ -1981,11 +1966,13 @@ export class ReflectionTransformer implements CustomTransformer {
1981
1966
importDeclaration = declaration . parent ;
1982
1967
}
1983
1968
1984
- // TODO: check if it's a built type here?
1985
-
1986
1969
if ( importDeclaration ) {
1987
1970
if ( importDeclaration . importClause && importDeclaration . importClause . isTypeOnly ) typeOnly = true ;
1988
1971
declaration = this . resolveImportSpecifier ( typeName . escapedText , importDeclaration , this . sourceFile ) ;
1972
+ if ( ! declaration ) {
1973
+ sourceFile = importDeclaration . getSourceFile ( ) ;
1974
+ declaration = this . resolveImportSpecifier ( typeName . escapedText , importDeclaration , sourceFile ) ;
1975
+ }
1989
1976
}
1990
1977
1991
1978
if ( declaration && declaration . kind === SyntaxKind . TypeParameter && declaration . parent . kind === SyntaxKind . TypeAliasDeclaration ) {
@@ -1995,7 +1982,7 @@ export class ReflectionTransformer implements CustomTransformer {
1995
1982
1996
1983
if ( ! declaration ) return ;
1997
1984
1998
- return { declaration, importDeclaration, typeOnly } ;
1985
+ return { declaration, importDeclaration, typeOnly, sourceFile } ;
1999
1986
}
2000
1987
2001
1988
// protected resolveType(node: TypeNode): Declaration | Node {
@@ -2031,17 +2018,11 @@ export class ReflectionTransformer implements CustomTransformer {
2031
2018
return this . f . createIdentifier ( '__Ω' + joinQualifiedName ( typeName ) ) ;
2032
2019
}
2033
2020
2034
- protected resolveImport ( declaration : Node , importDeclaration : ImportDeclaration , typeName : Identifier , program : CompilerProgram ) {
2035
- if ( isVariableDeclaration ( declaration ) ) {
2036
- if ( declaration . type ) {
2037
- declaration = declaration . type ;
2038
- } else if ( declaration . initializer ) {
2039
- declaration = declaration . initializer ;
2040
- }
2041
- }
2042
-
2021
+ protected resolveImport < T extends Expression > ( declaration : Node , importDeclaration : ImportDeclaration , typeName : Identifier , expression : T , program : CompilerProgram ) : CallExpression | T {
2043
2022
ensureImportIsEmitted ( importDeclaration , typeName ) ;
2044
2023
2024
+ if ( isTypeAliasDeclaration ( declaration ) ) return expression ;
2025
+
2045
2026
// check if the referenced declaration has reflection disabled
2046
2027
const declarationReflection = this . findReflectionConfig ( declaration , program ) ;
2047
2028
if ( declarationReflection . mode !== 'never' ) {
@@ -2055,19 +2036,33 @@ export class ReflectionTransformer implements CustomTransformer {
2055
2036
this . embedDeclarations . set ( declaration , {
2056
2037
name : typeName ,
2057
2038
sourceFile : declarationSourceFile ,
2058
- assignType : true ,
2059
2039
} ) ;
2040
+ // if (!isTypeAliasDeclaration(declaration)) {
2041
+ return this . wrapWithAssignType ( expression , runtimeTypeName ) ;
2042
+ // }
2060
2043
}
2061
2044
}
2045
+
2046
+ return expression ;
2062
2047
}
2063
2048
2064
- // TODO: what to do when the external type depends on another external type? should that be automatically resolved, or should the user explicitly specify that as well?
2065
2049
protected shouldInlineExternalImport ( importDeclaration : ImportDeclaration , entityName : EntityName , config : ReflectionConfig ) : boolean {
2066
- if ( ! ts . isStringLiteral ( importDeclaration . moduleSpecifier ) ) return false ;
2050
+ if ( ! isStringLiteral ( importDeclaration . moduleSpecifier ) ) return false ;
2067
2051
if ( config . options . inlineExternalImports === true ) return true ;
2068
- const externalImport = config . options . inlineExternalImports ?. [ importDeclaration . moduleSpecifier . text ] ;
2052
+ const resolvedModule = this . resolver . resolveImpl ( importDeclaration . moduleSpecifier . text , importDeclaration . getSourceFile ( ) . fileName ) ;
2053
+ if ( ! resolvedModule ) {
2054
+ throw new Error ( 'Cannot resolve module' ) ;
2055
+ }
2056
+ if ( ! resolvedModule . packageId ) {
2057
+ throw new Error ( 'Missing package id for resolved module' ) ;
2058
+ }
2059
+ if ( ! resolvedModule . isExternalLibraryImport ) {
2060
+ throw new Error ( 'Resolved module is not an external library import' ) ;
2061
+ }
2062
+ const externalImport = config . options . inlineExternalImports ?. [ resolvedModule . packageId . name ] ;
2069
2063
if ( ! externalImport ) return false ;
2070
2064
if ( externalImport === true ) return true ;
2065
+ if ( ! importDeclaration . moduleSpecifier . text . startsWith ( resolvedModule . packageId . name ) ) return true ;
2071
2066
const typeName = getEntityName ( entityName ) ;
2072
2067
return externalImport . includes ( typeName ) ;
2073
2068
}
@@ -2169,14 +2164,15 @@ export class ReflectionTransformer implements CustomTransformer {
2169
2164
}
2170
2165
2171
2166
if ( isModuleDeclaration ( declaration ) && resolved . importDeclaration ) {
2167
+ let expression : SerializedEntityNameAsExpression | CallExpression = serializeEntityNameAsExpression ( this . f , typeName ) ;
2172
2168
if ( isIdentifier ( typeName ) ) {
2173
- this . resolveImport ( declaration , resolved . importDeclaration , typeName , program ) ;
2169
+ expression = this . resolveImport ( declaration , resolved . importDeclaration , typeName , expression , program )
2174
2170
}
2175
2171
2176
2172
//we can not infer from module declaration, so do `typeof T` in runtime
2177
2173
program . pushOp (
2178
2174
ReflectionOp . typeof ,
2179
- program . pushStack ( this . f . createArrowFunction ( undefined , undefined , [ ] , undefined , undefined , serializeEntityNameAsExpression ( this . f , typeName ) ) )
2175
+ program . pushStack ( this . f . createArrowFunction ( undefined , undefined , [ ] , undefined , undefined , expression ) )
2180
2176
) ;
2181
2177
} else if ( isTypeAliasDeclaration ( declaration ) || isInterfaceDeclaration ( declaration ) || isEnumDeclaration ( declaration ) ) {
2182
2178
//Set/Map are interface declarations
@@ -2232,7 +2228,6 @@ export class ReflectionTransformer implements CustomTransformer {
2232
2228
}
2233
2229
2234
2230
if ( isGlobal ) {
2235
- //we don't embed non-global imported declarations anymore, only globals
2236
2231
this . embedDeclarations . set ( declaration , {
2237
2232
name : typeName ,
2238
2233
sourceFile : declarationSourceFile
@@ -2252,7 +2247,7 @@ export class ReflectionTransformer implements CustomTransformer {
2252
2247
return ;
2253
2248
}
2254
2249
2255
- const found = this . resolver . resolve ( this . sourceFile , resolved . importDeclaration ) ;
2250
+ const found = this . resolver . resolve ( resolved . sourceFile , resolved . importDeclaration ) ;
2256
2251
if ( ! found ) {
2257
2252
debug ( 'module not found' ) ;
2258
2253
program . pushOp ( ReflectionOp . any ) ;
@@ -2326,16 +2321,16 @@ export class ReflectionTransformer implements CustomTransformer {
2326
2321
return ;
2327
2322
}
2328
2323
2324
+ let body : Identifier | PropertyAccessExpression | CallExpression = isIdentifier ( typeName ) ? typeName : this . createAccessorForEntityName ( typeName ) ;
2329
2325
if ( resolved . importDeclaration && isIdentifier ( typeName ) ) {
2330
- this . resolveImport ( resolved . declaration , resolved . importDeclaration , typeName , program ) ;
2326
+ body = this . resolveImport ( resolved . declaration , resolved . importDeclaration , typeName , body , program ) ;
2331
2327
}
2332
2328
program . pushFrame ( ) ;
2333
2329
if ( type . typeArguments ) {
2334
2330
for ( const typeArgument of type . typeArguments ) {
2335
2331
this . extractPackStructOfType ( typeArgument , program ) ;
2336
2332
}
2337
2333
}
2338
- const body = isIdentifier ( typeName ) ? typeName : this . createAccessorForEntityName ( typeName ) ;
2339
2334
const index = program . pushStack ( this . f . createArrowFunction ( undefined , undefined , [ ] , undefined , undefined , body ) ) ;
2340
2335
program . pushOp ( isClassDeclaration ( declaration ) ? ReflectionOp . classReference : ReflectionOp . functionReference , index ) ;
2341
2336
program . popFrameImplicit ( ) ;
0 commit comments