@@ -36,13 +36,15 @@ namespace ts {
36
36
case ValueKind . FunctionOrClass :
37
37
return [ ...exportEquals ( ) , ...functionOrClassToStatements ( modifiers , name , info ) ] ;
38
38
case ValueKind . Object :
39
- const { members } = info ;
40
- if ( kind === OutputKind . ExportEquals ) {
41
- return flatMap ( members , v => toStatements ( v , OutputKind . NamedExport ) ) ;
42
- }
43
- if ( members . some ( m => m . kind === ValueKind . FunctionOrClass ) ) {
44
- // If some member is a function, use a namespace so it gets a FunctionDeclaration or ClassDeclaration.
45
- return [ ...exportDefault ( ) , createNamespace ( modifiers , name , flatMap ( members , toNamespaceMemberStatements ) ) ] ;
39
+ const { members, hasNontrivialPrototype } = info ;
40
+ if ( ! hasNontrivialPrototype ) {
41
+ if ( kind === OutputKind . ExportEquals ) {
42
+ return flatMap ( members , v => toStatements ( v , OutputKind . NamedExport ) ) ;
43
+ }
44
+ if ( members . some ( m => m . kind === ValueKind . FunctionOrClass ) ) {
45
+ // If some member is a function, use a namespace so it gets a FunctionDeclaration or ClassDeclaration.
46
+ return [ ...exportDefault ( ) , createNamespace ( modifiers , name , flatMap ( members , toNamespaceMemberStatements ) ) ] ;
47
+ }
46
48
}
47
49
// falls through
48
50
case ValueKind . Const :
@@ -62,10 +64,20 @@ namespace ts {
62
64
function functionOrClassToStatements ( modifiers : Modifiers , name : string , { source, prototypeMembers, namespaceMembers } : ValueInfoFunctionOrClass ) : ReadonlyArray < Statement > {
63
65
const fnAst = parseClassOrFunctionBody ( source ) ;
64
66
const { parameters, returnType } = fnAst === undefined ? { parameters : emptyArray , returnType : anyType ( ) } : getParametersAndReturnType ( fnAst ) ;
65
- const instanceProperties = typeof fnAst === "object" ? getConstructorFunctionInstanceProperties ( fnAst ) : emptyArray ;
67
+ const protoOrInstanceMembers = createMap < MethodDeclaration | PropertyDeclaration > ( ) ;
68
+ if ( typeof fnAst === "object" ) getConstructorFunctionInstanceProperties ( fnAst , protoOrInstanceMembers ) ;
69
+ for ( const p of prototypeMembers ) {
70
+ // ignore non-functions on the prototype
71
+ if ( p . kind === ValueKind . FunctionOrClass ) {
72
+ const m = tryGetMethod ( p ) ;
73
+ if ( m ) {
74
+ protoOrInstanceMembers . set ( p . name , m ) ;
75
+ }
76
+ }
77
+ }
66
78
67
79
const classStaticMembers : ClassElement [ ] | undefined =
68
- instanceProperties . length !== 0 || prototypeMembers . length !== 0 || fnAst === undefined || typeof fnAst !== "number" && fnAst . kind === SyntaxKind . Constructor ? [ ] : undefined ;
80
+ protoOrInstanceMembers . size !== 0 || fnAst === undefined || typeof fnAst !== "number" && fnAst . kind === SyntaxKind . Constructor ? [ ] : undefined ;
69
81
70
82
const namespaceStatements = flatMap ( namespaceMembers , info => {
71
83
if ( ! isValidIdentifier ( info . name ) ) return undefined ;
@@ -91,6 +103,9 @@ namespace ts {
91
103
return undefined ;
92
104
}
93
105
}
106
+ break ;
107
+ default :
108
+ Debug . assertNever ( info ) ;
94
109
}
95
110
}
96
111
return toStatements ( info , OutputKind . NamespaceMember ) ;
@@ -106,9 +121,7 @@ namespace ts {
106
121
[
107
122
...classStaticMembers ,
108
123
...( parameters . length ? [ createConstructor ( /*decorators*/ undefined , /*modifiers*/ undefined , parameters , /*body*/ undefined ) ] : emptyArray ) ,
109
- ...instanceProperties ,
110
- // ignore non-functions on the prototype
111
- ...mapDefined ( prototypeMembers , info => info . kind === ValueKind . FunctionOrClass ? tryGetMethod ( info ) : undefined ) ,
124
+ ...arrayFrom ( protoOrInstanceMembers . values ( ) ) ,
112
125
] )
113
126
: createFunctionDeclaration ( /*decorators*/ undefined , modifiers , /*asteriskToken*/ undefined , name , /*typeParameters*/ undefined , parameters , returnType , /*body*/ undefined ) ;
114
127
return [ decl , ...( namespaceStatements . length === 0 ? emptyArray : [ createNamespace ( modifiers && modifiers . map ( m => getSynthesizedDeepClone ( m ) ) , name , namespaceStatements ) ] ) ] ;
@@ -150,16 +163,16 @@ namespace ts {
150
163
}
151
164
152
165
// Parses assignments to "this.x" in the constructor into class property declarations
153
- function getConstructorFunctionInstanceProperties ( fnAst : FunctionOrConstructorNode ) : ReadonlyArray < PropertyDeclaration > {
154
- const members : PropertyDeclaration [ ] = [ ] ;
166
+ function getConstructorFunctionInstanceProperties ( fnAst : FunctionOrConstructorNode , members : Map < MethodDeclaration | PropertyDeclaration > ) : void {
155
167
forEachOwnNodeOfFunction ( fnAst , node => {
156
168
if ( isAssignmentExpression ( node , /*excludeCompoundAssignment*/ true ) &&
157
169
isPropertyAccessExpression ( node . left ) && node . left . expression . kind === SyntaxKind . ThisKeyword ) {
158
170
const name = node . left . name . text ;
159
- if ( ! isJsPrivate ( name ) ) members . push ( createProperty ( /*decorators*/ undefined , /*modifiers*/ undefined , name , /*questionOrExclamationToken*/ undefined , anyType ( ) , /*initializer*/ undefined ) ) ;
171
+ if ( ! isJsPrivate ( name ) ) {
172
+ getOrUpdate ( members , name , ( ) => createProperty ( /*decorators*/ undefined , /*modifiers*/ undefined , name , /*questionOrExclamationToken*/ undefined , anyType ( ) , /*initializer*/ undefined ) ) ;
173
+ }
160
174
}
161
175
} ) ;
162
- return members ;
163
176
}
164
177
165
178
interface ParametersAndReturnType { readonly parameters : ReadonlyArray < ParameterDeclaration > ; readonly returnType : TypeNode ; }
0 commit comments