@@ -36,13 +36,15 @@ namespace ts {
3636 case ValueKind . FunctionOrClass :
3737 return [ ...exportEquals ( ) , ...functionOrClassToStatements ( modifiers , name , info ) ] ;
3838 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+ }
4648 }
4749 // falls through
4850 case ValueKind . Const :
@@ -62,10 +64,20 @@ namespace ts {
6264 function functionOrClassToStatements ( modifiers : Modifiers , name : string , { source, prototypeMembers, namespaceMembers } : ValueInfoFunctionOrClass ) : ReadonlyArray < Statement > {
6365 const fnAst = parseClassOrFunctionBody ( source ) ;
6466 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+ }
6678
6779 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 ;
6981
7082 const namespaceStatements = flatMap ( namespaceMembers , info => {
7183 if ( ! isValidIdentifier ( info . name ) ) return undefined ;
@@ -91,6 +103,9 @@ namespace ts {
91103 return undefined ;
92104 }
93105 }
106+ break ;
107+ default :
108+ Debug . assertNever ( info ) ;
94109 }
95110 }
96111 return toStatements ( info , OutputKind . NamespaceMember ) ;
@@ -106,9 +121,7 @@ namespace ts {
106121 [
107122 ...classStaticMembers ,
108123 ...( 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 ( ) ) ,
112125 ] )
113126 : createFunctionDeclaration ( /*decorators*/ undefined , modifiers , /*asteriskToken*/ undefined , name , /*typeParameters*/ undefined , parameters , returnType , /*body*/ undefined ) ;
114127 return [ decl , ...( namespaceStatements . length === 0 ? emptyArray : [ createNamespace ( modifiers && modifiers . map ( m => getSynthesizedDeepClone ( m ) ) , name , namespaceStatements ) ] ) ] ;
@@ -150,16 +163,16 @@ namespace ts {
150163 }
151164
152165 // 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 {
155167 forEachOwnNodeOfFunction ( fnAst , node => {
156168 if ( isAssignmentExpression ( node , /*excludeCompoundAssignment*/ true ) &&
157169 isPropertyAccessExpression ( node . left ) && node . left . expression . kind === SyntaxKind . ThisKeyword ) {
158170 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+ }
160174 }
161175 } ) ;
162- return members ;
163176 }
164177
165178 interface ParametersAndReturnType { readonly parameters : ReadonlyArray < ParameterDeclaration > ; readonly returnType : TypeNode ; }
0 commit comments