namespace ts . codefix { param possiblyMissingSymbols param importAdder returns export function createMissingMemberNodes ( classDeclaration , possiblyMissingSymbols , sourceFile , context , preferences , importAdder , addClassElement ) { const classMembers = classDeclaration . symbol . members ! ; for ( const symbol of possiblyMissingSymbols ) { if ( ! classMembers . has ( symbol . escapedName ) ) { addNewNodeForMemberSymbol ( symbol , classDeclaration , sourceFile , context , preferences , importAdder , addClassElement , undefined ) ; } } } export function getNoopSymbolTrackerWithResolver ( context ) { return { trackSymbol : ( ) => false , moduleResolverHost : getModuleSpecifierResolverHost ( context . program , context . host ) , } ; } export interface TypeConstructionContext { program : Program ; host : LanguageServiceHost ; } type AddNode = PropertyDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction ; export const enum PreserveOptionalFlags { Method = 1 << 0 , Property = 1 << 1 , All = Method | Property } param body export function addNewNodeForMemberSymbol ( symbol , enclosingDeclaration , sourceFile , context , preferences , importAdder , addClassElement , body , preserveOptional = PreserveOptionalFlags . All , isAmbient = false ) { const declarations = symbol . getDeclarations ( ) ; if ( ! ( declarations && declarations . length ) ) { return undefined ; } const checker = context . program . getTypeChecker ( ) ; const scriptTarget = getEmitScriptTarget ( context . program . getCompilerOptions ( ) ) ; const declaration = declarations [ 0 ] ; const name = getSynthesizedDeepClone ( getNameOfDeclaration ( declaration ) , false ) as PropertyName ; const visibilityModifier = createVisibilityModifier ( getEffectiveModifierFlags ( declaration ) ) ; const modifiers = visibilityModifier ? factory . createNodeArray ( [ visibilityModifier ] ) : undefined ; const type = checker . getWidenedType ( checker . getTypeOfSymbolAtLocation ( symbol , enclosingDeclaration ) ) ; const optional = ! ! ( symbol . flags & SymbolFlags . Optional ) ; const ambient = ! ! ( enclosingDeclaration . flags & NodeFlags . Ambient ) || isAmbient ; const quotePreference = getQuotePreference ( sourceFile , preferences ) ; switch ( declaration . kind ) { case SyntaxKind . PropertySignature : case SyntaxKind . PropertyDeclaration : const flags = quotePreference === QuotePreference . Single ? NodeBuilderFlags . UseSingleQuotesForStringLiteralType : undefined ; let typeNode = checker . typeToTypeNode ( type , enclosingDeclaration , flags , getNoopSymbolTrackerWithResolver ( context ) ) ; if ( importAdder ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( typeNode , scriptTarget ) ; if ( importableReference ) { typeNode = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } } addClassElement ( factory . createPropertyDeclaration ( undefined , modifiers , name , optional && ( preserveOptional & PreserveOptionalFlags . Property ) ? factory . createToken ( SyntaxKind . QuestionToken ) : undefined , typeNode , undefined ) ) ; break ; case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : { let typeNode = checker . typeToTypeNode ( type , enclosingDeclaration , undefined , getNoopSymbolTrackerWithResolver ( context ) ) ; const allAccessors = getAllAccessorDeclarations ( declarations , declaration as AccessorDeclaration ) ; const orderedAccessors = allAccessors . secondAccessor ? [ allAccessors . firstAccessor , allAccessors . secondAccessor ] : [ allAccessors . firstAccessor ] ; if ( importAdder ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( typeNode , scriptTarget ) ; if ( importableReference ) { typeNode = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } } for ( const accessor of orderedAccessors ) { if ( isGetAccessorDeclaration ( accessor ) ) { addClassElement ( factory . createGetAccessorDeclaration ( undefined , modifiers , name , emptyArray , typeNode , ambient ? undefined : body || createStubbedMethodBody ( quotePreference ) ) ) ; } else { Debug . assertNode ( accessor , isSetAccessorDeclaration , "The counterpart to a getter should be a setter" ) ; const parameter = getSetAccessorValueParameter ( accessor ) ; const parameterName = parameter && isIdentifier ( parameter . name ) ? idText ( parameter . name ) : undefined ; addClassElement ( factory . createSetAccessorDeclaration ( undefined , modifiers , name , createDummyParameters ( 1 , [ parameterName ] , [ typeNode ] , 1 , false ) , ambient ? undefined : body || createStubbedMethodBody ( quotePreference ) ) ) ; } } break ; } case SyntaxKind . MethodSignature : case SyntaxKind . MethodDeclaration : const signatures = checker . getSignaturesOfType ( type , SignatureKind . Call ) ; if ( ! some ( signatures ) ) { break ; } if ( declarations . length === 1 ) { Debug . assert ( signatures . length === 1 , "One declaration implies one signature" ) ; const signature = signatures [ 0 ] ; outputMethod ( quotePreference , signature , modifiers , name , ambient ? undefined : body || createStubbedMethodBody ( quotePreference ) ) ; break ; } for ( const signature of signatures ) { outputMethod ( quotePreference , signature , getSynthesizedDeepClones ( modifiers , false ) , getSynthesizedDeepClone ( name , false ) ) ; } if ( ! ambient ) { if ( declarations . length > signatures . length ) { const signature = checker . getSignatureFromDeclaration ( declarations [ declarations . length - 1 ] as SignatureDeclaration ) ! ; outputMethod ( quotePreference , signature , modifiers , name , body || createStubbedMethodBody ( quotePreference ) ) ; } else { Debug . assert ( declarations . length === signatures . length , "Declarations and signatures should match count" ) ; addClassElement ( createMethodImplementingSignatures ( checker , context , enclosingDeclaration , signatures , name , optional && ! ! ( preserveOptional & PreserveOptionalFlags . Method ) , modifiers , quotePreference , body ) ) ; } } break ; } function outputMethod ( quotePreference , signature , modifiers , name , body ? ) { const method = createSignatureDeclarationFromSignature ( SyntaxKind . MethodDeclaration , context , quotePreference , signature , body , name , modifiers , optional && ! ! ( preserveOptional & PreserveOptionalFlags . Method ) , enclosingDeclaration , importAdder ) ; if ( method ) addClassElement ( method ) ; } } export function createSignatureDeclarationFromSignature ( kind , context , quotePreference , signature , body , name , modifiers , optional , enclosingDeclaration , importAdder ) { const program = context . program ; const checker = program . getTypeChecker ( ) ; const scriptTarget = getEmitScriptTarget ( program . getCompilerOptions ( ) ) ; const flags = NodeBuilderFlags . NoTruncation | NodeBuilderFlags . NoUndefinedOptionalParameterType | NodeBuilderFlags . SuppressAnyReturnType | ( quotePreference === QuotePreference . Single ? NodeBuilderFlags . UseSingleQuotesForStringLiteralType : 0 ) ; const signatureDeclaration = checker . signatureToSignatureDeclaration ( signature , kind , enclosingDeclaration , flags , getNoopSymbolTrackerWithResolver ( context ) ) as ArrowFunction | FunctionExpression | MethodDeclaration ; if ( ! signatureDeclaration ) { return undefined ; } let typeParameters = signatureDeclaration . typeParameters ; let parameters = signatureDeclaration . parameters ; let type = signatureDeclaration . type ; if ( importAdder ) { if ( typeParameters ) { const newTypeParameters = sameMap ( typeParameters , typeParameterDecl => { let constraint = typeParameterDecl . constraint ; let defaultType = typeParameterDecl . default ; if ( constraint ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( constraint , scriptTarget ) ; if ( importableReference ) { constraint = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } } if ( defaultType ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( defaultType , scriptTarget ) ; if ( importableReference ) { defaultType = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } } return factory . updateTypeParameterDeclaration ( typeParameterDecl , typeParameterDecl . name , constraint , defaultType ) ; } ) ; if ( typeParameters !== newTypeParameters ) { typeParameters = setTextRange ( factory . createNodeArray ( newTypeParameters , typeParameters . hasTrailingComma ) , typeParameters ) ; } } const newParameters = sameMap ( parameters , parameterDecl => { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( parameterDecl . type , scriptTarget ) ; let type = parameterDecl . type ; if ( importableReference ) { type = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } return factory . updateParameterDeclaration ( parameterDecl , parameterDecl . decorators , parameterDecl . modifiers , parameterDecl . dotDotDotToken , parameterDecl . name , parameterDecl . questionToken , type , parameterDecl . initializer ) ; } ) ; if ( parameters !== newParameters ) { parameters = setTextRange ( factory . createNodeArray ( newParameters , parameters . hasTrailingComma ) , parameters ) ; } if ( type ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( type , scriptTarget ) ; if ( importableReference ) { type = importableReference . typeNode ; importSymbols ( importAdder , importableReference . symbols ) ; } } } const questionToken = optional ? factory . createToken ( SyntaxKind . QuestionToken ) : undefined ; const asteriskToken = signatureDeclaration . asteriskToken ; if ( isFunctionExpression ( signatureDeclaration ) ) { return factory . updateFunctionExpression ( signatureDeclaration , modifiers , signatureDeclaration . asteriskToken , tryCast ( name , isIdentifier ) , typeParameters , parameters , type , body ?? signatureDeclaration . body ) ; } if ( isArrowFunction ( signatureDeclaration ) ) { return factory . updateArrowFunction ( signatureDeclaration , modifiers , typeParameters , parameters , type , signatureDeclaration . equalsGreaterThanToken , body ?? signatureDeclaration . body ) ; } if ( isMethodDeclaration ( signatureDeclaration ) ) { return factory . updateMethodDeclaration ( signatureDeclaration , undefined , modifiers , asteriskToken , name ?? factory . createIdentifier ( "" ) , questionToken , typeParameters , parameters , type , body ) ; } return undefined ; } export function createSignatureDeclarationFromCallExpression ( kind , context , importAdder , call , name , modifierFlags , contextNode ) { const quotePreference = getQuotePreference ( context . sourceFile , context . preferences ) ; const scriptTarget = getEmitScriptTarget ( context . program . getCompilerOptions ( ) ) ; const tracker = getNoopSymbolTrackerWithResolver ( context ) ; const checker = context . program . getTypeChecker ( ) ; const isJs = isInJSFile ( contextNode ) ; const { typeArguments , arguments : args , parent } = call ; const contextualType = isJs ? undefined : checker . getContextualType ( call ) ; const names = map ( args , arg => isIdentifier ( arg ) ? arg . text : isPropertyAccessExpression ( arg ) && isIdentifier ( arg . name ) ? arg . name . text : undefined ) ; const types = isJs ? [ ] : map ( args , arg => typeToAutoImportableTypeNode ( checker , importAdder , checker . getBaseTypeOfLiteralType ( checker . getTypeAtLocation ( arg ) ) , contextNode , scriptTarget , undefined , tracker ) ) ; const modifiers = modifierFlags ? factory . createNodeArray ( factory . createModifiersFromModifierFlags ( modifierFlags ) ) : undefined ; const asteriskToken = isYieldExpression ( parent ) ? factory . createToken ( SyntaxKind . AsteriskToken ) : undefined ; const typeParameters = isJs || typeArguments === undefined ? undefined : map ( typeArguments , ( _ , i ) => factory . createTypeParameterDeclaration ( CharacterCodes . T + typeArguments . length - 1 <= CharacterCodes . Z ? String . fromCharCode ( CharacterCodes . T + i ) : `T${ i }` ) ) ; const parameters = createDummyParameters ( args . length , names , types , undefined , isJs ) ; const type = isJs || contextualType === undefined ? undefined : checker . typeToTypeNode ( contextualType , contextNode , undefined , tracker ) ; if ( kind === SyntaxKind . MethodDeclaration ) { return factory . createMethodDeclaration ( undefined , modifiers , asteriskToken , name , undefined , typeParameters , parameters , type , isInterfaceDeclaration ( contextNode ) ? undefined : createStubbedMethodBody ( quotePreference ) ) ; } return factory . createFunctionDeclaration ( undefined , modifiers , asteriskToken , name , typeParameters , parameters , type , createStubbedBody ( Diagnostics . Function_not_implemented . message , quotePreference ) ) ; } export function typeToAutoImportableTypeNode ( checker , importAdder , type , contextNode , scriptTarget , flags ? , tracker ? ) { let typeNode = checker . typeToTypeNode ( type , contextNode , flags , tracker ) ; if ( typeNode && isImportTypeNode ( typeNode ) ) { const importableReference = tryGetAutoImportableReferenceFromTypeNode ( typeNode , scriptTarget ) ; if ( importableReference ) { importSymbols ( importAdder , importableReference . symbols ) ; typeNode = importableReference . typeNode ; } } return getSynthesizedDeepClone ( typeNode ) ; } function createDummyParameters ( argCount , names , types , minArgumentCount , inJs ) { const parameters = [ ] ; for ( let i = 0 ; i < argCount ; i ++ ) { const newParameter = factory . createParameterDeclaration ( undefined , undefined , undefined , names && names [ i ] || `arg${ i }` , minArgumentCount !== undefined && i >= minArgumentCount ? factory . createToken ( SyntaxKind . QuestionToken ) : undefined , inJs ? undefined : types && types [ i ] || factory . createKeywordTypeNode ( SyntaxKind . AnyKeyword ) , undefined ) ; parameters . push ( newParameter ) ; } return parameters ; } function createMethodImplementingSignatures ( checker , context , enclosingDeclaration , signatures , name , optional , modifiers , quotePreference , body ) { /** This is *a* signature with the maximal number of arguments,
         * such that if there is a "maximal" signature without rest arguments,
         * this is one of them.
         */ let maxArgsSignature = signatures [ 0 ] ; let minArgumentCount = signatures [ 0 ] . minArgumentCount ; let someSigHasRestParameter = false ; for ( const sig of signatures ) { minArgumentCount = Math . min ( sig . minArgumentCount , minArgumentCount ) ; if ( signatureHasRestParameter ( sig ) ) { someSigHasRestParameter = true ; } if ( sig . parameters . length >= maxArgsSignature . parameters . length && ( ! signatureHasRestParameter ( sig ) || signatureHasRestParameter ( maxArgsSignature ) ) ) { maxArgsSignature = sig ; } } const maxNonRestArgs = maxArgsSignature . parameters . length - ( signatureHasRestParameter ( maxArgsSignature ) ? 1 : 0 ) ; const maxArgsParameterSymbolNames = maxArgsSignature . parameters . map ( symbol => symbol . name ) ; const parameters = createDummyParameters ( maxNonRestArgs , maxArgsParameterSymbolNames , undefined , minArgumentCount , false ) ; if ( someSigHasRestParameter ) { const anyArrayType = factory . createArrayTypeNode ( factory . createKeywordTypeNode ( SyntaxKind . AnyKeyword ) ) ; const restParameter = factory . createParameterDeclaration ( undefined , undefined , factory . createToken ( SyntaxKind . DotDotDotToken ) , maxArgsParameterSymbolNames [ maxNonRestArgs ] || "rest" , maxNonRestArgs >= minArgumentCount ? factory . createToken ( SyntaxKind . QuestionToken ) : undefined , anyArrayType , undefined ) ; parameters . push ( restParameter ) ; } return createStubbedMethod ( modifiers , name , optional , undefined , parameters , getReturnTypeFromSignatures ( signatures , checker , context , enclosingDeclaration ) , quotePreference , body ) ; } function getReturnTypeFromSignatures ( signatures , checker , context , enclosingDeclaration ) { if ( length ( signatures ) ) { const type = checker . getUnionType ( map ( signatures , checker . getReturnTypeOfSignature ) ) ; return checker . typeToTypeNode ( type , enclosingDeclaration , undefined , getNoopSymbolTrackerWithResolver ( context ) ) ; } } function createStubbedMethod ( modifiers , name , optional , typeParameters , parameters , returnType , quotePreference , body ) { return factory . createMethodDeclaration ( undefined , modifiers , undefined , name , optional ? factory . createToken ( SyntaxKind . QuestionToken ) : undefined , typeParameters , parameters , returnType , body || createStubbedMethodBody ( quotePreference ) ) ; } function createStubbedMethodBody ( quotePreference ) { return createStubbedBody ( Diagnostics . Method_not_implemented . message , quotePreference ) ; } export function createStubbedBody ( text , quotePreference ) { return factory . createBlock ( [ factory . createThrowStatement ( factory . createNewExpression ( factory . createIdentifier ( "Error" ) , undefined , [ factory . createStringLiteral ( text , quotePreference === QuotePreference . Single ) ] ) ) ] , true ) ; } function createVisibilityModifier ( flags ) { if ( flags & ModifierFlags . Public ) { return factory . createToken ( SyntaxKind . PublicKeyword ) ; } else if ( flags & ModifierFlags . Protected ) { return factory . createToken ( SyntaxKind . ProtectedKeyword ) ; } return undefined ; } export function setJsonCompilerOptionValues ( changeTracker , configFile , options ) { const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression ( configFile ) ; if ( ! tsconfigObjectLiteral ) return undefined ; const compilerOptionsProperty = findJsonProperty ( tsconfigObjectLiteral , "compilerOptions" ) ; if ( compilerOptionsProperty === undefined ) { changeTracker . insertNodeAtObjectStart ( configFile , tsconfigObjectLiteral , createJsonPropertyAssignment ( "compilerOptions" , factory . createObjectLiteralExpression ( options . map ( ( [ optionName , optionValue ] ) => createJsonPropertyAssignment ( optionName , optionValue ) ) , true ) ) ) ; return ; } const compilerOptions = compilerOptionsProperty . initializer ; if ( ! isObjectLiteralExpression ( compilerOptions ) ) { return ; } for ( const [ optionName , optionValue ] of options ) { const optionProperty = findJsonProperty ( compilerOptions , optionName ) ; if ( optionProperty === undefined ) { changeTracker . insertNodeAtObjectStart ( configFile , compilerOptions , createJsonPropertyAssignment ( optionName , optionValue ) ) ; } else { changeTracker . replaceNode ( configFile , optionProperty . initializer , optionValue ) ; } } } export function setJsonCompilerOptionValue ( changeTracker , configFile , optionName , optionValue ) { setJsonCompilerOptionValues ( changeTracker , configFile , [ [ optionName , optionValue ] ] ) ; } export function createJsonPropertyAssignment ( name , initializer ) { return factory . createPropertyAssignment ( factory . createStringLiteral ( name ) , initializer ) ; } export function findJsonProperty ( obj , name ) { return find ( obj . properties , ( p ) : p is PropertyAssignment => isPropertyAssignment ( p ) && ! ! p . name && isStringLiteral ( p . name ) && p . name . text === name ) ; } /**
     * Given a type node containing 'import("./a").SomeType<import("./b").OtherType<...>>',
     * returns an equivalent type reference node with any nested ImportTypeNodes also replaced
     * with type references, and a list of symbols that must be imported to use the type reference.
     */ export function tryGetAutoImportableReferenceFromTypeNode ( importTypeNode , scriptTarget ) { let symbols ; const typeNode = visitNode ( importTypeNode , visit ) ; if ( symbols && typeNode ) { return { typeNode , symbols } ; } function visit ( node ) ; function visit ( node ) { if ( isLiteralImportTypeNode ( node ) && node . qualifier ) { const firstIdentifier = getFirstIdentifier ( node . qualifier ) ; const name = getNameForExportedSymbol ( firstIdentifier . symbol , scriptTarget ) ; const qualifier = name !== firstIdentifier . text ? replaceFirstIdentifierOfEntityName ( node . qualifier , factory . createIdentifier ( name ) ) : node . qualifier ; symbols = append ( symbols , firstIdentifier . symbol ) ; const typeArguments = node . typeArguments ?. map ( visit ) ; return factory . createTypeReferenceNode ( qualifier , typeArguments ) ; } return visitEachChild ( node , visit , nullTransformationContext ) ; } } function replaceFirstIdentifierOfEntityName ( name , newIdentifier ) { if ( name . kind === SyntaxKind . Identifier ) { return newIdentifier ; } return factory . createQualifiedName ( replaceFirstIdentifierOfEntityName ( name . left , newIdentifier ) , name . right ) ; } export function importSymbols ( importAdder , symbols ) { symbols . forEach ( s => importAdder . addImportFromExportedSymbol ( s , true ) ) ; } }