file author meixuguang
  import * as ts from 'byots' ; import { formatMethodName } from './utilities/method' ; import { SyntaxKind , ListFormat , SourceFile , Symbol , Node , isImportSpecifier , isBlock , createTextWriter } from 'byots' ; import { nodeIsSynthesized , isIdentifier , idText , getLiteralText , getEmitFlags , rangeEndIsOnSameLineAsRangeStart , rangeIsOnSingleLine , positionIsSynthesized , rangeEndPositionsAreOnSameLine , isPrologueDirective , rangeStartPositionsAreOnSameLine } from './utilities' ; import * as utilities from './utilities' ; import { shouldAddDollar , shouldUseArray , shouldAddDoubleQuote , isVisibilityModifier , isSupportedPropertyModifier , isStringLike , isClassLike , isClassInstance , isFunctionLike , isVariable , shouldUseReference , isFromImport } from './utilities/nodeTest' ; import { CompilerState } from './types' ; import { isRelativePath , hasRequired , markRequired } from './utilities/index' ; import { getRequireOnceCode } from './utilities/makeCode' ; let currentSourceFile ; const enum TempFlags { Auto = 0x00000000 , CountMask = 0x0FFFFFFF , _i = 0x10000000 } export function emitFile ( sourceFile , state , resolver , transformers ? ) { const brackets = createBracketsMap ( ) ; currentSourceFile = sourceFile ; let tempFlagsStack ; let tempFlags ; let reservedNamesStack ; let reservedNames ; let write = writeBase ; reset ( ) ; const writer = createTextWriter ( '\n' ) ; writer . writeLine ( ) ; const typeChecker = state . typeChecker ; state . helpers = { emit , emitLiteral , emitWithHint , emitExpression , emitExpressionList , getLiteralTextOfNode , getTextOfNode , writeLine , writePunctuation , writeSpace , writeBase } ; const transform = ts . transformNodes ( resolver , undefined , { } , [ sourceFile ] , transformers ! , false ) ; state . sourceFile = ( transform . transformed [ 0 ] as SourceFile ) ; if ( state . emitHeader ) { let header = '<?php\n' ; if ( state . namespace && state . namespace !== '\\' ) { header += `namespace ${ state . namespace };\n` ; } writer . write ( header ) ; } state . sourceFile . forEachChild ( ( node ) => { emit ( node ) ; writer . writeLine ( ) ; } ) ; return writer . getText ( ) ; function reset ( ) { tempFlagsStack = [ ] ; tempFlags = TempFlags . Auto ; reservedNamesStack = [ ] ; } function emit ( node ) { if ( ! node ) return ; emitWithHint ( ts . EmitHint . Unspecified , node ) ; } function emitIdentifierName ( node ) { if ( ! node ) return ; emitWithHint ( ts . EmitHint . IdentifierName , node ) ; } function createBracketsMap ( ) { const brackets = [ ] ; brackets [ ts . ListFormat . Braces ] = [ '{' , '}' ] ; brackets [ ts . ListFormat . Parenthesis ] = [ '(' , ')' ] ; brackets [ ts . ListFormat . AngleBrackets ] = [ '<' , '>' ] ; brackets [ ts . ListFormat . SquareBrackets ] = [ '[' , ']' ] ; return brackets ; } function getOpeningBracket ( format ) { return ( shouldUseArray ( format ) && shouldUseArray ( format ) [ 0 ] ) || brackets [ format & ts . ListFormat . BracketsMask ] [ 0 ] ; } function getClosingBracket ( format ) { return ( shouldUseArray ( format ) && shouldUseArray ( format ) [ 1 ] ) || brackets [ format & ts . ListFormat . BracketsMask ] [ 1 ] ; } function emitExpression ( node ) { if ( ! node ) return ; emitWithHint ( ts . EmitHint . Expression , node ) ; } function emitWithHint ( hint , node ) { for ( const plugin of state . plugins ) { const output = plugin . emit ( hint , node , state ) ; if ( output !== false ) { return ; } } if ( hint === ts . EmitHint . IdentifierName ) return emitIdentifier ( ts . cast ( node , isIdentifier ) ) ; if ( hint === ts . EmitHint . Unspecified ) { switch ( node . kind ) { case SyntaxKind . TemplateHead : case SyntaxKind . TemplateMiddle : case SyntaxKind . TemplateTail : return emitLiteral ( < ts . LiteralExpression > node ) ; case SyntaxKind . Identifier : return emitIdentifier ( < ts . Identifier > node ) ; case SyntaxKind . ComputedPropertyName : return emitComputedPropertyName ( < ts . ComputedPropertyName > node ) ; case SyntaxKind . Parameter : return emitParameter ( < ts . ParameterDeclaration > node ) ; case SyntaxKind . PropertyDeclaration : return emitPropertyDeclaration ( < ts . PropertyDeclaration > node ) ; case SyntaxKind . MethodDeclaration : return emitMethodDeclaration ( < ts . MethodDeclaration > node ) ; case SyntaxKind . Constructor : return emitConstructor ( < ts . ConstructorDeclaration > node ) ; case SyntaxKind . ExpressionWithTypeArguments : return emitExpressionWithTypeArguments ( < ts . ExpressionWithTypeArguments > node ) ; case SyntaxKind . ArrayBindingPattern : return emitArrayBindingPattern ( < ts . ArrayBindingPattern > node ) ; case SyntaxKind . BindingElement : return emitBindingElement ( < ts . BindingElement > node ) ; case SyntaxKind . TemplateSpan : return emitTemplateSpan ( < ts . TemplateSpan > node ) ; case SyntaxKind . Block : return emitBlock ( < ts . Block > node ) ; case SyntaxKind . VariableStatement : return emitVariableStatement ( < ts . VariableStatement > node ) ; case SyntaxKind . ExpressionStatement : return emitExpressionStatement ( < ts . ExpressionStatement > node ) ; case SyntaxKind . IfStatement : return emitIfStatement ( < ts . IfStatement > node ) ; case SyntaxKind . DoStatement : return emitDoStatement ( < ts . DoStatement > node ) ; case SyntaxKind . WhileStatement : return emitWhileStatement ( < ts . WhileStatement > node ) ; case SyntaxKind . ForStatement : return emitForStatement ( < ts . ForStatement > node ) ; case SyntaxKind . ForInStatement : return emitForInStatement ( < ts . ForInStatement > node ) ; case SyntaxKind . ForOfStatement : return emitForOfStatement ( < ts . ForOfStatement > node ) ; case SyntaxKind . ContinueStatement : return emitContinueStatement ( < ts . ContinueStatement > node ) ; case SyntaxKind . BreakStatement : return emitBreakStatement ( < ts . BreakStatement > node ) ; case SyntaxKind . ReturnStatement : return emitReturnStatement ( < ts . ReturnStatement > node ) ; case SyntaxKind . SwitchStatement : return emitSwitchStatement ( < ts . SwitchStatement > node ) ; case SyntaxKind . ThrowStatement : return emitThrowStatement ( < ts . ThrowStatement > node ) ; case SyntaxKind . TryStatement : return emitTryStatement ( < ts . TryStatement > node ) ; case SyntaxKind . StaticKeyword : case SyntaxKind . PublicKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : case SyntaxKind . AbstractKeyword : writeTokenNode ( node , writeKeyword ) ; return ; case SyntaxKind . VariableDeclaration : return emitVariableDeclaration ( < ts . VariableDeclaration > node ) ; case SyntaxKind . VariableDeclarationList : return emitVariableDeclarationList ( < ts . VariableDeclarationList > node ) ; case SyntaxKind . FunctionDeclaration : return emitFunctionDeclaration ( < ts . FunctionDeclaration > node ) ; case SyntaxKind . ClassDeclaration : return emitClassDeclaration ( < ts . ClassDeclaration > node ) ; case SyntaxKind . CaseBlock : return emitCaseBlock ( < ts . CaseBlock > node ) ; case SyntaxKind . ImportDeclaration : return emitImportDeclaration ( < ts . ImportDeclaration > node ) ; case SyntaxKind . ImportClause : return emitImportClause ( < ts . ImportClause > node ) ; case SyntaxKind . NamedImports : return emitNamedImports ( < ts . NamedImports > node ) ; case SyntaxKind . ImportSpecifier : return emitImportSpecifier ( < ts . ImportSpecifier > node ) ; case SyntaxKind . ExportAssignment : return emitExportAssignment ( < ts . ExportAssignment > node ) ; case SyntaxKind . ExportDeclaration : return emitExportDeclaration ( < ts . ExportDeclaration > node ) ; case SyntaxKind . CaseClause : return emitCaseClause ( < ts . CaseClause > node ) ; case SyntaxKind . DefaultClause : return emitDefaultClause ( < ts . DefaultClause > node ) ; case SyntaxKind . HeritageClause : return emitHeritageClause ( < ts . HeritageClause > node ) ; case SyntaxKind . CatchClause : return emitCatchClause ( < ts . CatchClause > node ) ; case SyntaxKind . PropertyAssignment : return emitPropertyAssignment ( < ts . PropertyAssignment > node ) ; case SyntaxKind . ShorthandPropertyAssignment : return emitShorthandPropertyAssignment ( < ts . ShorthandPropertyAssignment > node ) ; } } if ( hint === ts . EmitHint . Expression ) { switch ( node . kind ) { case SyntaxKind . NumericLiteral : return emitNumericLiteral ( < ts . NumericLiteral > node ) ; case SyntaxKind . RegularExpressionLiteral : return emitRegularExpressionLiteral ( < ts . RegularExpressionLiteral > node ) ; case SyntaxKind . StringLiteral : case SyntaxKind . NoSubstitutionTemplateLiteral : return emitLiteral ( < ts . LiteralExpression > node ) ; case SyntaxKind . Identifier : return emitIdentifier ( < ts . Identifier > node ) ; case SyntaxKind . FalseKeyword : case SyntaxKind . NullKeyword : case SyntaxKind . SuperKeyword : case SyntaxKind . TrueKeyword : case SyntaxKind . ThisKeyword : case SyntaxKind . ImportKeyword : writeTokenNode ( node , writeKeyword ) ; return ; case SyntaxKind . ArrayLiteralExpression : return emitArrayLiteralExpression ( < ts . ArrayLiteralExpression > node ) ; case SyntaxKind . ObjectLiteralExpression : return emitObjectLiteralExpression ( < ts . ObjectLiteralExpression > node ) ; case SyntaxKind . PropertyAccessExpression : return emitPropertyAccessExpression ( < ts . PropertyAccessExpression > node ) ; case SyntaxKind . ElementAccessExpression : return emitElementAccessExpression ( < ts . ElementAccessExpression > node ) ; case SyntaxKind . CallExpression : return emitCallExpression ( < ts . CallExpression > node ) ; case SyntaxKind . NewExpression : return emitNewExpression ( < ts . NewExpression > node ) ; case SyntaxKind . TypeAssertionExpression : return emitTypeAssertionExpression ( < ts . TypeAssertion > node ) ; case SyntaxKind . ParenthesizedExpression : return emitParenthesizedExpression ( < ts . ParenthesizedExpression > node ) ; case SyntaxKind . FunctionExpression : return emitFunctionExpression ( < ts . FunctionExpression > node ) ; case SyntaxKind . ArrowFunction : return emitArrowFunction ( < ts . ArrowFunction > node ) ; case SyntaxKind . DeleteExpression : return emitDeleteExpression ( < ts . DeleteExpression > node ) ; case SyntaxKind . TypeOfExpression : return emitTypeOfExpression ( < ts . TypeOfExpression > node ) ; case SyntaxKind . PrefixUnaryExpression : return emitPrefixUnaryExpression ( < ts . PrefixUnaryExpression > node ) ; case SyntaxKind . PostfixUnaryExpression : return emitPostfixUnaryExpression ( < ts . PostfixUnaryExpression > node ) ; case SyntaxKind . BinaryExpression : return emitBinaryExpression ( < ts . BinaryExpression > node ) ; case SyntaxKind . ConditionalExpression : return emitConditionalExpression ( < ts . ConditionalExpression > node ) ; case SyntaxKind . TemplateExpression : return emitTemplateExpression ( < ts . TemplateExpression > node ) ; case SyntaxKind . SpreadElement : return emitSpreadExpression ( < ts . SpreadElement > node ) ; case SyntaxKind . ClassExpression : return emitClassExpression ( < ts . ClassExpression > node ) ; case SyntaxKind . OmittedExpression : return ; case SyntaxKind . AsExpression : return emitAsExpression ( < ts . AsExpression > node ) ; } } } function emitNumericLiteral ( node ) { emitLiteral ( node ) ; } function emitRegularExpressionLiteral ( node ) { const text = JSON . stringify ( getLiteralTextOfNode ( node , true ) . replace ( /\/[^/]+$/ , match => match . replace ( 'g' , '' ) ) ) ; writeStringLiteral ( text ) ; } function emitLiteral ( node ) { let text = getLiteralTextOfNode ( node , true ) ; text = text . replace ( /(\\)?\$/g , '\\$' ) ; writeStringLiteral ( text ) ; } function emitIdentifier ( node ) { const writeText = node . symbol ? writeSymbol : writeBase ; const nodeText = getTextOfNode ( node , false ) ; writeText ( nodeText , node . symbol ) ; } function emitComputedPropertyName ( node ) { writePunctuation ( '(' ) ; emitExpression ( node . expression ) ; writePunctuation ( ')' ) ; } function emitParameter ( node ) { emitNodeWithWriter ( node . name , writeParameter ) ; if ( node . parent && node . parent . kind === SyntaxKind . JSDocFunctionType && ! node . name ) { emit ( node . type ) ; } else { emitTypeAnnotation ( node . type ) ; } if ( node . questionToken && ! node . initializer ) { node . initializer = ts . createNull ( ) ; node . initializer . parent = node ; ts . setTextRange ( node . initializer , node ) ; } emitInitializer ( node . initializer , node . type ? node . type . end : node . questionToken ? node . questionToken . end : node . name ? node . name . end : node . modifiers ? node . modifiers . end : node . decorators ? node . decorators . end : node . pos , node ) ; } function emitPropertyDeclaration ( node ) { const modifiers = ( node . modifiers || [ ] as any as ts . NodeArray < ts . Modifier > ) . filter ( isSupportedPropertyModifier ) as any as ts . NodeArray < ts . Modifier > ; const hasVisibilityModifier = modifiers . some ( isVisibilityModifier ) ; if ( ! hasVisibilityModifier ) { writeKeyword ( 'public' ) ; writeSpace ( ) ; } emitModifiers ( node , modifiers ) ; emit ( node . name ) ; emitInitializer ( node . initializer , node . type ? node . type . end : node . questionToken ? node . questionToken . end : node . name . end , node ) ; writeSemicolon ( ) ; } function emitMethodDeclaration ( node ) { emitModifiers ( node , node . modifiers ) ; if ( ts . isClassDeclaration ( node . parent || node . original . parent ) ) { writeKeyword ( 'function' ) ; writeSpace ( ) ; emit ( node . name ) ; } else { writer . write ( '"' ) ; emit ( node . name ) ; writer . write ( '"' ) ; writeSpace ( ) ; writer . write ( '=>' ) ; writeSpace ( ) ; writeKeyword ( 'function' ) ; writeSpace ( ) ; } emitSignatureAndBody ( node , emitSignatureHead ) ; } function emitConstructor ( node ) { writeKeyword ( 'function' ) ; writeSpace ( ) ; writeKeyword ( '__construct' ) ; emitSignatureAndBody ( node , emitSignatureHead ) ; } function emitArrayBindingPattern ( node ) { writePunctuation ( 'list(' ) ; emitList ( node , node . elements , ListFormat . ArrayBindingPatternElements ) ; writePunctuation ( ')' ) ; } function emitBindingElement ( node ) { emit ( node . name ) ; } function emitArrayLiteralExpression ( node ) { const elements = node . elements ; const preferNewLine = node . multiLine ? ts . ListFormat . PreferNewLine : ts . ListFormat . None ; emitExpressionList ( node , elements , ts . ListFormat . ArrayLiteralExpressionElements | preferNewLine ) ; } function emitObjectLiteralExpression ( node ) { const preferNewLine = node . multiLine ? ts . ListFormat . PreferNewLine : ts . ListFormat . None ; const allowTrailingComma = ts . ListFormat . None ; emitList ( node , node . properties , ts . ListFormat . ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine ) ; } function emitPropertyAccessExpression ( node ) { const { prefix , suffix } = utilities . getAccessPrefixAndSuffix ( node , typeChecker ) ; emitWithHint ( ts . EmitHint . Expression , node . expression ) ; writePunctuation ( prefix ) ; emitWithHint ( ts . EmitHint . Unspecified , node . name ) ; writePunctuation ( suffix ) ; } function emitElementAccessExpression ( node ) { const { prefix , suffix } = utilities . getAccessPrefixAndSuffix ( node , typeChecker ) ; emitExpression ( node . expression ) ; writePunctuation ( prefix ) ; emitExpression ( node . argumentExpression ) ; writePunctuation ( suffix ) ; } function emitCallExpression ( node ) { if ( ts . isIdentifier ( node . expression ) && isFunctionLike ( node . expression , typeChecker ) && isVariable ( node . expression , typeChecker ) ) { writeBase ( '$' ) ; } const writeNamespace = emitIdentifierFromImport ( node . expression ) ; if ( ! writeNamespace ) { emitWithHint ( ts . EmitHint . Expression , node . expression ) ; } emitExpressionList ( node , node . arguments , ts . ListFormat . CallExpressionArguments ) ; } function emitNewExpression ( node ) { let openParenPos ; if ( node . parent && node . parent . kind === ts . SyntaxKind . PropertyAccessExpression && ( node . parent as ts . PropertyAccessExpression ) . expression === node ) { openParenPos = emitTokenWithComment ( SyntaxKind . OpenParenToken , node . pos , writePunctuation , node ) ; } emitTokenWithComment ( SyntaxKind . NewKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; emitExpression ( node . expression ) ; emitExpressionList ( node , node . arguments , ListFormat . NewExpressionArguments ) ; openParenPos !== undefined && emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression ? node . expression . end : openParenPos , writePunctuation , node ) ; } function emitTypeAssertionExpression ( node ) { emitExpression ( node . expression ) ; } function emitParenthesizedExpression ( node ) { const openParenPos = emitTokenWithComment ( SyntaxKind . OpenParenToken , node . pos , writePunctuation , node ) ; emitExpression ( node . expression ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression ? node . expression . end : openParenPos , writePunctuation , node ) ; } function emitFunctionExpression ( node ) { emitFunctionDeclarationOrExpression ( node ) ; } function emitArrowFunction ( node ) { emitSignatureAndBody ( node , emitArrowFunctionHead ) ; } function emitArrowFunctionHead ( node ) { writeKeyword ( 'function' ) ; writeSpace ( ) ; emitParametersForArrow ( node , node . parameters ) ; } function emitDeleteExpression ( node ) { writePunctuation ( 'unset(' ) ; emitExpression ( node . expression ) ; writePunctuation ( ')' ) ; } function emitTypeOfExpression ( node ) { const funcName = formatMethodName ( '%helper::typeof' , state . helperNamespace ) ; writePunctuation ( `${ funcName }(` ) ; emitExpression ( node . expression ) ; writePunctuation ( ')' ) ; } function emitPrefixUnaryExpression ( node ) { writeTokenText ( node . operator , writeOperator ) ; if ( shouldEmitWhitespaceBeforeOperand ( node ) ) { writeSpace ( ) ; } emitExpression ( node . operand ) ; } function shouldEmitWhitespaceBeforeOperand ( node ) { const operand = node . operand ; return operand . kind === SyntaxKind . PrefixUnaryExpression && ( ( node . operator === SyntaxKind . PlusToken && ( ( < ts . PrefixUnaryExpression > operand ) . operator === SyntaxKind . PlusToken || ( < ts . PrefixUnaryExpression > operand ) . operator === SyntaxKind . PlusPlusToken ) ) || ( node . operator === SyntaxKind . MinusToken && ( ( < ts . PrefixUnaryExpression > operand ) . operator === SyntaxKind . MinusToken || ( < ts . PrefixUnaryExpression > operand ) . operator === SyntaxKind . MinusMinusToken ) ) ) ; } function emitPostfixUnaryExpression ( node ) { emitExpression ( node . operand ) ; writeTokenText ( node . operator , writeOperator ) ; } function emitBinaryExpression ( node ) { emitWithHint ( ts . EmitHint . Expression , node . left ) ; writeSpace ( ) ; if ( node . operatorToken . kind === ts . SyntaxKind . PlusEqualsToken && ( isStringLike ( node . left , typeChecker ) || isStringLike ( node . right , typeChecker ) ) ) { writePunctuation ( '.=' ) ; } else if ( node . operatorToken . kind === ts . SyntaxKind . BarBarToken ) { writePunctuation ( '?:' ) ; } else { writeTokenNode ( node . operatorToken , writeOperator , node . left , node . right ) ; } writeSpace ( ) ; emitWithHint ( ts . EmitHint . Expression , node . right ) ; } function emitConditionalExpression ( node ) { const indentBeforeQuestion = needsIndentation ( node , node . condition , node . questionToken ) ; const indentAfterQuestion = needsIndentation ( node , node . questionToken , node . whenTrue ) ; const indentBeforeColon = needsIndentation ( node , node . whenTrue , node . colonToken ) ; const indentAfterColon = needsIndentation ( node , node . colonToken , node . whenFalse ) ; emitExpression ( node . condition ) ; increaseIndentIf ( indentBeforeQuestion , ' ' ) ; writePunctuation ( '?' ) ; increaseIndentIf ( indentAfterQuestion , ' ' ) ; emitExpression ( node . whenTrue ) ; decreaseIndentIf ( indentBeforeQuestion , indentAfterQuestion ) ; increaseIndentIf ( indentBeforeColon , ' ' ) ; writePunctuation ( ':' ) ; increaseIndentIf ( indentAfterColon , ' ' ) ; emitExpression ( node . whenFalse ) ; decreaseIndentIf ( indentBeforeColon , indentAfterColon ) ; } function emitTemplateExpression ( node ) { emit ( node . head ) ; emitList ( node , node . templateSpans , ts . ListFormat . TemplateExpressionSpans ) ; } function emitSpreadExpression ( node ) { state . errors . push ( ts . createDiagnosticForNodeInSourceFile ( sourceFile , node , { category : ts . DiagnosticCategory . Error , message : 'Spread expression is not supported yet!' , code : 5555 , key : 'ts2php' } ) ) ; } function emitClassExpression ( node ) { emitClassDeclarationOrExpression ( node ) ; } function emitExpressionWithTypeArguments ( node ) { emitExpression ( node . expression ) ; } function emitAsExpression ( node ) { emitExpression ( node . expression ) ; } function emitTemplateSpan ( node ) { writeSpace ( ) ; const needQuote = ( ! ts . isIdentifier ( node . expression ) && ! ts . isElementAccessExpression ( node . expression ) && ! ts . isPropertyAccessExpression ( node . expression ) && ! ts . isCallExpression ( node . expression ) && ! ts . isParenthesizedExpression ( node . expression ) ) ; if ( needQuote ) { writePunctuation ( '(' ) ; } emitExpression ( node . expression ) ; if ( needQuote ) { writePunctuation ( ')' ) ; } emit ( node . literal ) ; } function emitBlock ( node ) { emitBlockStatements ( node , ! node . multiLine && isEmptyBlock ( node ) ) ; } function emitBlockStatements ( node , forceSingleLine ) { emitTokenWithComment ( SyntaxKind . OpenBraceToken , node . pos , writePunctuation , node ) ; const format = forceSingleLine || getEmitFlags ( node ) & ts . EmitFlags . SingleLine ? ts . ListFormat . SingleLineBlockStatements : ts . ListFormat . MultiLineBlockStatements ; emitList ( node , node . statements , format ) ; emitTokenWithComment ( SyntaxKind . CloseBraceToken , node . statements . end , writePunctuation , node , ! ! ( format & ts . ListFormat . MultiLine ) ) ; } function emitVariableStatement ( node ) { emit ( node . declarationList ) ; writeSemicolon ( ) ; } function emitExpressionStatement ( node ) { emitWithHint ( ts . EmitHint . Expression , node . expression ) ; writeSemicolon ( ) ; } function emitIfStatement ( node ) { const openParenPos = emitTokenWithComment ( SyntaxKind . IfKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitExpression ( node . expression ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression . end , writePunctuation , node ) ; emitEmbeddedStatement ( node , node . thenStatement ) ; if ( node . elseStatement ) { writeLineOrSpace ( node ) ; emitTokenWithComment ( SyntaxKind . ElseKeyword , node . thenStatement . end , writeKeyword , node ) ; if ( node . elseStatement . kind === SyntaxKind . IfStatement ) { writeSpace ( ) ; emit ( node . elseStatement ) ; } else { emitEmbeddedStatement ( node , node . elseStatement ) ; } } } function emitWhileClause ( node , startPos ) { const openParenPos = emitTokenWithComment ( SyntaxKind . WhileKeyword , startPos , writeKeyword , node ) ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitExpression ( node . expression ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression . end , writePunctuation , node ) ; } function emitDoStatement ( node ) { emitTokenWithComment ( SyntaxKind . DoKeyword , node . pos , writeKeyword , node ) ; emitEmbeddedStatement ( node , node . statement ) ; if ( isBlock ( node . statement ) ) { writeSpace ( ) ; } else { writeLineOrSpace ( node ) ; } emitWhileClause ( node , node . statement . end ) ; writePunctuation ( ';' ) ; } function emitWhileStatement ( node ) { emitWhileClause ( node , node . pos ) ; emitEmbeddedStatement ( node , node . statement ) ; } function emitForStatement ( node ) { const openParenPos = emitTokenWithComment ( SyntaxKind . ForKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; let pos = emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitForBinding ( node . initializer ) ; pos = emitTokenWithComment ( SyntaxKind . SemicolonToken , node . initializer ? node . initializer . end : pos , writeSemicolon , node ) ; emitExpressionWithLeadingSpace ( node . condition ) ; pos = emitTokenWithComment ( SyntaxKind . SemicolonToken , node . condition ? node . condition . end : pos , writeSemicolon , node ) ; emitExpressionWithLeadingSpace ( node . incrementor ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . incrementor ? node . incrementor . end : pos , writePunctuation , node ) ; emitEmbeddedStatement ( node , node . statement ) ; } function emitForInStatement ( node ) { writeKeyword ( 'foreach' ) ; const openParenPos = node . pos ! < 0 ? node . pos ! : node . pos ! + 7 ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitExpression ( node . expression ) ; writeSpace ( ) ; writeKeyword ( 'as' ) ; writeSpace ( ) ; emitForBinding ( node . initializer ) ; writeSpace ( ) ; writeKeyword ( '=>' ) ; writeSpace ( ) ; writeBase ( '$__ts2php_item' ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression . end , writePunctuation , node ) ; emitEmbeddedStatement ( node , node . statement ) ; } function emitForOfStatement ( node ) { writeKeyword ( 'foreach' ) ; const openParenPos = node . pos ! < 0 ? node . pos ! : node . pos ! + 7 ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitExpression ( node . expression ) ; writeSpace ( ) ; writeKeyword ( 'as' ) ; writeSpace ( ) ; emitForBinding ( node . initializer ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression . end , writePunctuation , node ) ; emitEmbeddedStatement ( node , node . statement ) ; } function emitForBinding ( node ) { if ( node !== undefined ) { if ( node . kind === SyntaxKind . VariableDeclarationList ) { emit ( node ) ; } else { emitExpression ( node ) ; } } } function emitContinueStatement ( node ) { emitTokenWithComment ( SyntaxKind . ContinueKeyword , node . pos , writeKeyword , node ) ; emitWithLeadingSpace ( node . label ) ; writeSemicolon ( ) ; } function emitBreakStatement ( node ) { emitTokenWithComment ( SyntaxKind . BreakKeyword , node . pos , writeKeyword , node ) ; emitWithLeadingSpace ( node . label ) ; writeSemicolon ( ) ; } function emitTokenWithComment ( token , pos , writer , contextNode , indentLeading ? ) { pos = writeTokenText ( token , writer , pos ) ; return pos ; } function emitReturnStatement ( node ) { emitTokenWithComment ( SyntaxKind . ReturnKeyword , node . pos , writeKeyword , node ) ; emitExpressionWithLeadingSpace ( node . expression ) ; writeSemicolon ( ) ; } function emitSwitchStatement ( node ) { const openParenPos = emitTokenWithComment ( SyntaxKind . SwitchKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitExpression ( node . expression ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . expression . end , writePunctuation , node ) ; writeSpace ( ) ; emit ( node . caseBlock ) ; } function emitThrowStatement ( node ) { if ( isStringLike ( node . expression , typeChecker ) ) { emitTokenWithComment ( SyntaxKind . ThrowKeyword , node . pos , writeKeyword , node ) ; emitExpressionWithLeadingSpace ( ts . createNew ( ts . createIdentifier ( '\\Exception' ) , undefined , [ node . expression ] ) ) ; writeSemicolon ( ) ; } if ( ts . isNewExpression ( node . expression ) && ts . isIdentifier ( node . expression . expression ) && node . expression . expression . getText ( ) === 'Error' ) { emitTokenWithComment ( SyntaxKind . ThrowKeyword , node . pos , writeKeyword , node ) ; emitExpressionWithLeadingSpace ( ts . createNew ( ts . createIdentifier ( '\\Exception' ) , undefined , [ node . expression . arguments [ 0 ] ] ) ) ; writeSemicolon ( ) ; } } function emitTryStatement ( node ) { emitTokenWithComment ( SyntaxKind . TryKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; emit ( node . tryBlock ) ; if ( node . catchClause ) { writeLineOrSpace ( node ) ; emit ( node . catchClause ) ; } if ( node . finallyBlock ) { writeLineOrSpace ( node ) ; emitTokenWithComment ( SyntaxKind . FinallyKeyword , ( node . catchClause || node . tryBlock ) . end , writeKeyword , node ) ; writeSpace ( ) ; emit ( node . finallyBlock ) ; } } function emitVariableDeclaration ( node ) { emit ( node . name ) ; emitInitializer ( node . initializer , node . type ? node . type . end : node . name . end , node ) ; } function emitVariableDeclarationList ( node ) { emitList ( node , node . declarations , ts . ListFormat . VariableDeclarationList ) ; } function emitFunctionDeclaration ( node ) { emitFunctionDeclarationOrExpression ( node ) ; } function emitFunctionDeclarationOrExpression ( node ) { writeKeyword ( 'function' ) ; writeSpace ( ) ; emitIdentifierName ( node . name ! ) ; emitSignatureAndBody ( node , emitSignatureHead ) ; } function emitSignatureAndBody ( node , emitSignatureHead ) { const body = node . body ; if ( body ) { if ( isBlock ( body ) ) { const indentedFlag = getEmitFlags ( node ) & ts . EmitFlags . Indented ; if ( indentedFlag ) { increaseIndent ( ) ; } pushNameGenerationScope ( node ) ; emitSignatureHead ( node ) ; emitInheritedVariables ( node ) ; emitBlockFunctionBody ( body ) ; popNameGenerationScope ( node ) ; if ( indentedFlag ) { decreaseIndent ( ) ; } } else { emitSignatureHead ( node ) ; emitInheritedVariables ( node ) ; writePunctuation ( '{' ) ; writeLine ( ) ; writeKeyword ( 'return' ) ; writeSpace ( ) ; emitExpression ( body ) ; writeSemicolon ( ) ; writeLine ( ) ; writePunctuation ( '}' ) ; } } else { emitSignatureHead ( node ) ; writeSemicolon ( ) ; } } function emitInheritedVariables ( node ) { if ( node . kind === ts . SyntaxKind . ArrowFunction || node . kind === ts . SyntaxKind . FunctionExpression || ( node . kind === ts . SyntaxKind . MethodDeclaration && ! ts . isClassDeclaration ( node . parent || node . original . parent ) ) || node . kind === ts . SyntaxKind . FunctionDeclaration ) { const identifiers = utilities . getDescendantIdentifiers ( node ) ; const inheritedVariables = [ ] ; const nodeStart = node . getStart ( state . sourceFile ) ; const nodeEnd = node . getEnd ( ) ; const names = { } ; identifiers . forEach ( item => { if ( item . parent && item . parent . kind === ts . SyntaxKind . PropertyAccessExpression && ( item . parent as ts . PropertyAccessExpression ) . name === item ) { return ; } if ( isClassLike ( item , typeChecker ) ) { return ; } if ( isFunctionLike ( item , typeChecker ) && ! isVariable ( item , typeChecker ) ) { return ; } const currentSourceFile = item . getSourceFile ( ) ; const symbolOfIdentifier = typeChecker . getSymbolAtLocation ( item ) ; if ( ! symbolOfIdentifier ) { return ; } const d = symbolOfIdentifier . getDeclarations ( ) ; const inherite = d . find ( item => ( item . getStart ( ) < nodeStart || item . getEnd ( ) > nodeEnd ) && item . getSourceFile ( ) . fileName === currentSourceFile . fileName ) ; if ( inherite ) { const text = item . getText ( ) ; if ( ! names [ text ] ) { names [ text ] = 1 ; inheritedVariables . push ( item ) ; } } } ) ; if ( inheritedVariables . length > 0 ) { if ( node . kind === ts . SyntaxKind . FunctionDeclaration ) { const { line , character } = state . sourceFile . getLineAndCharacterOfPosition ( node . getStart ( state . sourceFile ) ) ; state . errors . push ( ts . createDiagnosticForNodeInSourceFile ( sourceFile , node , { category : ts . DiagnosticCategory . Error , message : `Function declaration can not use outside variables, use anonymous function instead.` , code : 5555 , key : 'ts2php' } ) ) ; return ; } writeSpace ( ) ; write ( 'use' ) ; writePunctuation ( '(' ) ; inheritedVariables . forEach ( ( item , index ) => { const text = item . getText ( ) ; write ( `&$${ text }` ) ; if ( index !== inheritedVariables . length - 1 ) { write ( ', ' ) ; } } ) ; writePunctuation ( ')' ) ; writeSpace ( ) ; } } } function emitSignatureHead ( node ) { emitParameters ( node , node . parameters ) ; } function shouldEmitBlockFunctionBodyOnSingleLine ( body ) { if ( getEmitFlags ( body ) & ts . EmitFlags . SingleLine ) { return true ; } if ( body . multiLine ) { return false ; } if ( ! nodeIsSynthesized ( body ) && ! rangeIsOnSingleLine ( body , currentSourceFile ) ) { return false ; } if ( shouldWriteLeadingLineTerminator ( body , body . statements , ts . ListFormat . PreserveLines ) || shouldWriteClosingLineTerminator ( body , body . statements , ts . ListFormat . PreserveLines ) ) { return false ; } let previousStatement ; for ( const statement of body . statements ) { if ( shouldWriteSeparatingLineTerminator ( previousStatement , statement , ts . ListFormat . PreserveLines ) ) { return false ; } previousStatement = statement ; } return true ; } function emitBlockFunctionBody ( body ) { writeSpace ( ) ; writePunctuation ( '{' ) ; increaseIndent ( ) ; const emitBlockFunctionBody = shouldEmitBlockFunctionBodyOnSingleLine ( body ) ? emitBlockFunctionBodyOnSingleLine : emitBlockFunctionBodyWorker ; emitBlockFunctionBody ( body ) ; decreaseIndent ( ) ; writeToken ( SyntaxKind . CloseBraceToken , body . statements . end , writePunctuation , body ) ; } function emitBlockFunctionBodyOnSingleLine ( body ) { emitBlockFunctionBodyWorker ( body , true ) ; } function emitBlockFunctionBodyWorker ( body , emitBlockFunctionBodyOnSingleLine ? ) { const statementOffset = emitPrologueDirectives ( body . statements , true ) ; const pos = writer . getTextPos ( ) ; if ( statementOffset === 0 && pos === writer . getTextPos ( ) && emitBlockFunctionBodyOnSingleLine ) { decreaseIndent ( ) ; emitList ( body , body . statements , ts . ListFormat . SingleLineFunctionBodyStatements ) ; increaseIndent ( ) ; } else { emitList ( body , body . statements , ts . ListFormat . MultiLineFunctionBodyStatements , statementOffset ) ; } } function emitClassDeclaration ( node ) { emitClassDeclarationOrExpression ( node ) ; } function emitClassDeclarationOrExpression ( node ) { if ( node . modifiers ) { node . modifiers = ts . createNodeArray ( node . modifiers . filter ( m => { return m . kind === ts . SyntaxKind . AbstractKeyword ; } ) ) ; } emitModifiers ( node , node . modifiers ) ; writeKeyword ( 'class' ) ; if ( node . name ) { writeSpace ( ) ; emitIdentifierName ( node . name ) ; } const indentedFlag = getEmitFlags ( node ) & ts . EmitFlags . Indented ; if ( indentedFlag ) { increaseIndent ( ) ; } if ( node . heritageClauses ) { node . heritageClauses = ts . createNodeArray ( node . heritageClauses . filter ( hc => { return hc . token !== ts . SyntaxKind . ImplementsKeyword ; } ) ) ; } if ( node . heritageClauses && node . heritageClauses . length > 0 ) { emitList ( node , node . heritageClauses , ListFormat . ClassHeritageClauses ) ; } writeSpace ( ) ; writePunctuation ( '{' ) ; emitList ( node , node . members , ListFormat . ClassMembers ) ; writePunctuation ( '}' ) ; if ( indentedFlag ) { decreaseIndent ( ) ; } } function emitCaseBlock ( node ) { emitTokenWithComment ( SyntaxKind . OpenBraceToken , node . pos , writePunctuation , node ) ; emitList ( node , node . clauses , ts . ListFormat . CaseBlockClauses ) ; emitTokenWithComment ( SyntaxKind . CloseBraceToken , node . clauses . end , writePunctuation , node , true ) ; } function emitImportDeclaration ( node ) { const { moduleName , modulePath } = getImportModuleName ( node ) ; const moduleIt = state . modules [ moduleName ] ; let validImportMember = false ; const isType = node => { const typeNode = node . symbol ? typeChecker . getDeclaredTypeOfSymbol ( node . symbol ) : undefined ; if ( ! typeNode ) { validImportMember = true ; return ; } if ( typeNode . aliasSymbol ) { return ; } const symbolFlags = typeNode . symbol ? typeNode . symbol . getFlags ( ) : true ; if ( symbolFlags !== ts . SymbolFlags . Interface ) { validImportMember = true ; } } ; if ( node . importClause ) { if ( node . importClause . name ) { isType ( node . importClause . name ) ; } if ( node . importClause . namedBindings ) { node . importClause . namedBindings . forEachChild ( isType ) ; } } if ( moduleIt && ! hasRequired ( moduleIt , moduleName , modulePath ) && validImportMember ) { writeBase ( getRequireOnceCode ( moduleName , modulePath , moduleIt ) ) ; writeSemicolon ( ) ; writeLine ( ) ; markRequired ( moduleIt , moduleName , modulePath ) ; } if ( node . importClause ) { emit ( node . importClause ) ; } } function emitImportClause ( node ) { emit ( node . namedBindings ) ; } function emitNamedImports ( node ) { emitNamedImportsOrExports ( node ) ; } function emitImportSpecifier ( node ) { emitImportOrExportSpecifier ( node ) ; } function emitExportAssignment ( node ) { emitExpression ( node . expression ) ; writeSemicolon ( ) ; } function emitExportDeclaration ( node ) { if ( node . moduleSpecifier ) { const { moduleName , modulePath } = getImportModuleName ( node ) ; const moduleIt = state . modules [ moduleName ] ; if ( moduleIt && ! hasRequired ( moduleIt , moduleName , modulePath ) ) { writeBase ( getRequireOnceCode ( moduleName , modulePath , moduleIt ) ) ; writeSemicolon ( ) ; writeLine ( ) ; markRequired ( moduleIt , moduleName , modulePath ) ; } } } function emitNamedImportsOrExports ( node ) { const importNode = node . parent . parent ; if ( ts . isImportDeclaration ( importNode ) ) { const { moduleName } = getImportModuleName ( importNode ) ; node . forEachChild ( ( element ) => { if ( isClassLike ( element . name , typeChecker ) ) { if ( state . modules [ moduleName ] && state . modules [ moduleName ] . used ) { return ; } writePunctuation ( 'use' ) ; writeSpace ( ) ; const namespace = state . modules [ moduleName ] && state . modules [ moduleName ] . namespace ; namespace && writeBase ( namespace ) ; emit ( element ) ; writeSemicolon ( ) ; writeLine ( ) ; } } ) ; } } function emitImportOrExportSpecifier ( node ) { if ( node . propertyName ) { emit ( node . propertyName ) ; writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . AsKeyword , node . propertyName . end , writeKeyword , node ) ; writeSpace ( ) ; } emit ( node . name ) ; } function emitCaseClause ( node ) { emitTokenWithComment ( SyntaxKind . CaseKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; emitExpression ( node . expression ) ; emitCaseOrDefaultClauseRest ( node , node . statements , node . expression . end ) ; } function emitDefaultClause ( node ) { const pos = emitTokenWithComment ( SyntaxKind . DefaultKeyword , node . pos , writeKeyword , node ) ; emitCaseOrDefaultClauseRest ( node , node . statements , pos ) ; } function emitCaseOrDefaultClauseRest ( parentNode , statements , colonPos ) { const emitAsSingleStatement = statements . length === 1 && ( nodeIsSynthesized ( parentNode ) || nodeIsSynthesized ( statements [ 0 ] ) || rangeStartPositionsAreOnSameLine ( parentNode , statements [ 0 ] , currentSourceFile ) ) ; let format = ts . ListFormat . CaseOrDefaultClauseStatements ; if ( emitAsSingleStatement ) { writeToken ( SyntaxKind . ColonToken , colonPos , writePunctuation , parentNode ) ; writeSpace ( ) ; format &= ~ ( ts . ListFormat . MultiLine | ts . ListFormat . Indented ) ; } else { emitTokenWithComment ( SyntaxKind . ColonToken , colonPos , writePunctuation , parentNode ) ; } emitList ( parentNode , statements , format ) ; } function emitHeritageClause ( node ) { writeSpace ( ) ; writeTokenText ( node . token , writeKeyword ) ; writeSpace ( ) ; emitList ( node , node . types , ListFormat . HeritageClauseTypes ) ; } function emitCatchClause ( node ) { const openParenPos = emitTokenWithComment ( SyntaxKind . CatchKeyword , node . pos , writeKeyword , node ) ; writeSpace ( ) ; if ( node . variableDeclaration ) { emitTokenWithComment ( SyntaxKind . OpenParenToken , openParenPos , writePunctuation , node ) ; emitIdentifier ( ts . createIdentifier ( '\\Exception' ) ) ; emitWithLeadingSpace ( node . variableDeclaration ) ; emitTokenWithComment ( SyntaxKind . CloseParenToken , node . variableDeclaration . end , writePunctuation , node ) ; writeSpace ( ) ; } emit ( node . block ) ; } function emitPropertyAssignment ( node ) { if ( ts . isLiteralExpression ( node . name ) ) { emitLiteral ( node . name ) ; } else if ( ts . isIdentifier ( node . name ) ) { emit ( node . name ) ; } else { emit ( node . name ) ; } writeSpace ( ) ; writePunctuation ( '=>' ) ; writeSpace ( ) ; if ( isFunctionLike ( node . initializer , typeChecker ) && ! isVariable ( node . initializer , typeChecker ) && ! ts . isFunctionLikeDeclaration ( node . initializer ) ) { writeBase ( '"' ) ; const fromImport = emitIdentifierFromImport ( node . initializer ) ; if ( ! fromImport ) { emit ( node . initializer ) ; } writeBase ( '"' ) ; } else { emitExpression ( node . initializer ) ; } } function emitShorthandPropertyAssignment ( node ) { writeBase ( '"' ) ; emit ( node . name ) ; writeBase ( '"' ) ; if ( node . objectAssignmentInitializer ) { writeSpace ( ) ; writePunctuation ( '=' ) ; writeSpace ( ) ; emitExpression ( node . objectAssignmentInitializer ) ; } else { writeSpace ( ) ; writePunctuation ( '=>' ) ; writeSpace ( ) ; if ( isFunctionLike ( node , typeChecker ) && ! isVariable ( node , typeChecker ) ) { writeBase ( '"' ) ; const fromImport = emitIdentifierFromImport ( node . name ) ; ! fromImport && emit ( node . name ) ; writeBase ( '"' ) ; } else { writeBase ( '$' ) ; emit ( node . name ) ; } } } /**
     * Emits any prologue directives at the start of a Statement list, returning the
     * number of prologue directives written to the output.
     */ function emitPrologueDirectives ( statements , startWithNewLine ? , seenPrologueDirectives ? ) { for ( let i = 0 ; i < statements . length ; i ++ ) { const statement = statements [ i ] ; if ( isPrologueDirective ( statement ) ) { const shouldEmitPrologueDirective = seenPrologueDirectives ? ! seenPrologueDirectives . has ( statement . expression . text ) : true ; if ( shouldEmitPrologueDirective ) { if ( startWithNewLine || i > 0 ) { writeLine ( ) ; } emit ( statement ) ; if ( seenPrologueDirectives ) { seenPrologueDirectives . set ( statement . expression . text , true ) ; } } } else { return i ; } } return statements . length ; } function emitNodeWithWriter ( node , writer ) { if ( ! node ) return ; const savedWrite = write ; write = writer ; emit ( node ) ; write = savedWrite ; } function emitModifiers ( node , modifiers ) { if ( modifiers && modifiers . length ) { emitList ( node , modifiers , ts . ListFormat . Modifiers ) ; writeSpace ( ) ; } } function emitTypeAnnotation ( node ) { } function emitInitializer ( node , equalCommentStartPos , container ) { if ( node ) { writeSpace ( ) ; emitTokenWithComment ( SyntaxKind . EqualsToken , equalCommentStartPos , writeOperator , container ) ; writeSpace ( ) ; if ( shouldUseReference ( node , typeChecker ) ) { writeBase ( '&' ) ; } emitExpression ( node ) ; } } function emitWithLeadingSpace ( node ) { if ( node ) { writeSpace ( ) ; emit ( node ) ; } } function emitExpressionWithLeadingSpace ( node ) { if ( node ) { writeSpace ( ) ; emitExpression ( node ) ; } } function emitWithTrailingSpace ( node ) { if ( node ) { emit ( node ) ; writeSpace ( ) ; } } function emitEmbeddedStatement ( parent , node ) { if ( isBlock ( node ) || getEmitFlags ( parent ) & ts . EmitFlags . SingleLine ) { writeSpace ( ) ; emit ( node ) ; } else { writeLine ( ) ; increaseIndent ( ) ; emit ( node ) ; decreaseIndent ( ) ; } } function emitDecorators ( parentNode , decorators ) { emitList ( parentNode , decorators , ts . ListFormat . Decorators ) ; } function emitTypeArguments ( parentNode , typeArguments ) { emitList ( parentNode , typeArguments , ts . ListFormat . TypeArguments ) ; } function emitParameters ( parentNode , parameters ) { emitList ( parentNode , parameters , ts . ListFormat . Parameters ) ; } function canEmitSimpleArrowHead ( parentNode , parameters ) { const parameter = ts . singleOrUndefined ( parameters ) ; return parameter && parameter . pos === parentNode . pos && ts . isArrowFunction ( parentNode ) && ! parentNode . type && ! ts . some ( parentNode . decorators ) && ! ts . some ( parentNode . modifiers ) && ! ts . some ( parentNode . typeParameters ) && ! ts . some ( parameter . decorators ) && ! ts . some ( parameter . modifiers ) && ! parameter . dotDotDotToken && ! parameter . questionToken && ! parameter . type && ! parameter . initializer && isIdentifier ( parameter . name ) ; } function emitParametersForArrow ( parentNode , parameters ) { if ( canEmitSimpleArrowHead ( parentNode , parameters ) ) { emitList ( parentNode , parameters , ( ListFormat . Parameters & ~ ListFormat . Parenthesis ) | ts . ListFormat . Parenthesis ) ; } else { emitParameters ( parentNode , parameters ) ; } } function emitList ( parentNode , children , format , start ? , count ? ) { emitNodeList ( emit , parentNode , children , format , start , count ) ; } function emitExpressionList ( parentNode , children , format , start ? , count ? ) { emitNodeList ( emitExpression as ( node : Node ) => void , parentNode , children , format , start , count ) ; } function writeDelimiter ( format ) { if ( format === ts . ListFormat . VariableDeclarationList ) { writePunctuation ( ';' ) ; return ; } switch ( format & ts . ListFormat . DelimitersMask ) { case ts . ListFormat . None : break ; case ts . ListFormat . CommaDelimited : writePunctuation ( ',' ) ; break ; case ts . ListFormat . BarDelimited : writeSpace ( ) ; writePunctuation ( '|' ) ; break ; case ts . ListFormat . AsteriskDelimited : writeSpace ( ) ; writePunctuation ( '*' ) ; writeSpace ( ) ; break ; case ts . ListFormat . AmpersandDelimited : writeSpace ( ) ; writePunctuation ( '&' ) ; break ; } } function emitNodeList ( emit , parentNode , children , format , start = 0 , count = children ? children . length - start : 0 ) { const isUndefined = children === undefined ; if ( isUndefined && format & ts . ListFormat . OptionalIfUndefined ) { return ; } const isEmpty = children === undefined || start >= children . length || count === 0 ; if ( isEmpty && format & ts . ListFormat . OptionalIfEmpty ) { return ; } if ( format & ts . ListFormat . BracketsMask ) { writePunctuation ( getOpeningBracket ( format ) ) ; } if ( isEmpty ) { if ( format & ts . ListFormat . MultiLine ) { writeLine ( ) ; } else if ( format & ts . ListFormat . SpaceBetweenBraces && ! ( format & ts . ListFormat . NoSpaceIfEmpty ) ) { writeSpace ( ) ; } } else { const mayEmitInterveningComments = ( format & ts . ListFormat . NoInterveningComments ) === 0 ; if ( shouldWriteLeadingLineTerminator ( parentNode , children ! , format ) ) { writeLine ( ) ; } else if ( format & ts . ListFormat . SpaceBetweenBraces ) { writeSpace ( ) ; } if ( format & ts . ListFormat . Indented ) { increaseIndent ( ) ; } let previousSibling ; for ( let i = 0 ; i < count ; i ++ ) { const child = children ! [ start + i ] ; if ( format & ts . ListFormat . AsteriskDelimited ) { writeLine ( ) ; writeDelimiter ( format ) ; } else if ( previousSibling ) { writeDelimiter ( format ) ; if ( shouldWriteSeparatingLineTerminator ( previousSibling , child , format ) ) { writeLine ( ) ; } else if ( previousSibling && format & ts . ListFormat . SpaceBetweenSiblings ) { writeSpace ( ) ; } } emit ( child ) ; previousSibling = child ; } const hasTrailingComma = ( format & ts . ListFormat . AllowTrailingComma ) && children ! . hasTrailingComma ; if ( format & ts . ListFormat . CommaDelimited && hasTrailingComma ) { writePunctuation ( ',' ) ; } if ( format & ts . ListFormat . Indented ) { decreaseIndent ( ) ; } if ( shouldWriteClosingLineTerminator ( parentNode , children ! , format ) ) { writeLine ( ) ; } else if ( format & ts . ListFormat . SpaceBetweenBraces ) { writeSpace ( ) ; } } if ( format & ts . ListFormat . BracketsMask ) { writePunctuation ( getClosingBracket ( format ) ) ; } } /**
     * identifier from import may need add namespace
     */ function emitIdentifierFromImport ( node ) { if ( ! ( ts . isIdentifier ( node ) && isFromImport ( node , typeChecker ) ) ) { return false ; } const symbol = typeChecker . getSymbolAtLocation ( node ) ; const declarations = symbol . getDeclarations ( ) ; const specifier = declarations [ 0 ] as ts . ImportSpecifier ; const declaration = specifier . parent . parent . parent as ts . ImportDeclaration ; const moduleName = declaration . moduleSpecifier . getText ( ) . replace ( /^['"]/ , '' ) . replace ( /['"]$/ , '' ) ; const namespace = state . modules [ moduleName ] && state . modules [ moduleName ] . namespace ; namespace && writeBase ( namespace ) ; emitExpression ( specifier . propertyName || specifier . name ) ; return true ; } function writeStringLiteral ( s ) { writer . writeStringLiteral ( s ) ; } function writeBase ( s ) { writer . write ( s ) ; } function writeSymbol ( s , sym ) { writer . writeSymbol ( s , sym ) ; } function writePunctuation ( s ) { writer . writePunctuation ( s ) ; } function writeSemicolon ( ) { writer . writePunctuation ( ';' ) ; } function writeKeyword ( s ) { writer . writeKeyword ( s ) ; } function writeOperator ( s ) { writer . writeOperator ( s ) ; } function writeParameter ( s ) { writer . writeParameter ( s ) ; } function writeSpace ( ) { writer . writeSpace ( ' ' ) ; } function writeLine ( ) { writer . writeLine ( ) ; } function increaseIndent ( ) { writer . increaseIndent ( ) ; } function decreaseIndent ( ) { writer . decreaseIndent ( ) ; } function writeToken ( token , pos , writer , contextNode ? ) { return writeTokenText ( token , writer , pos ) ; } function writeTokenNode ( node , writer , left ? , right ? ) { if ( node . kind === SyntaxKind . PlusToken ) { if ( isStringLike ( left , typeChecker ) || isStringLike ( right , typeChecker ) ) { writer ( '.' ) ; return ; } } if ( node . kind === SyntaxKind . ThisKeyword ) { writer ( '$' ) ; } if ( node . kind === SyntaxKind . SuperKeyword && ts . isCallExpression ( node . parent ) ) { writer ( 'parent::__construct' ) ; return ; } if ( node . kind === SyntaxKind . SuperKeyword && ts . isPropertyAccessExpression ( node . parent ) ) { writer ( 'parent' ) ; return ; } writer ( ts . tokenToString ( node . kind ) ! ) ; } function writeTokenText ( token , writer ) ; function writeTokenText ( token , writer , pos ) ; function writeTokenText ( token , writer , pos ? ) { const tokenString = ts . tokenToString ( token ) ! ; writer ( tokenString ) ; return pos ! < 0 ? pos ! : pos ! + tokenString . length ; } function writeLineOrSpace ( node ) { if ( getEmitFlags ( node ) & ts . EmitFlags . SingleLine ) { writeSpace ( ) ; } else { writeLine ( ) ; } } function increaseIndentIf ( value , valueToWriteWhenNotIndenting ? ) { if ( value ) { increaseIndent ( ) ; writeLine ( ) ; } else if ( valueToWriteWhenNotIndenting ) { write ( valueToWriteWhenNotIndenting ) ; } } function decreaseIndentIf ( value1 , value2 ? ) { if ( value1 ) { decreaseIndent ( ) ; } if ( value2 ) { decreaseIndent ( ) ; } } function shouldWriteLeadingLineTerminator ( parentNode , children , format ) { if ( format & ts . ListFormat . MultiLine ) { return true ; } if ( format & ts . ListFormat . PreserveLines ) { if ( format & ts . ListFormat . PreferNewLine ) { return true ; } } else { return false ; } } function shouldWriteSeparatingLineTerminator ( previousNode , nextNode , format ) { if ( format & ts . ListFormat . MultiLine ) { return true ; } else if ( format & ts . ListFormat . PreserveLines ) { if ( previousNode === undefined || nextNode === undefined ) { return false ; } else if ( nodeIsSynthesized ( previousNode ) || nodeIsSynthesized ( nextNode ) ) { return synthesizedNodeStartsOnNewLine ( previousNode , format ) || synthesizedNodeStartsOnNewLine ( nextNode , format ) ; } else { return ! rangeEndIsOnSameLineAsRangeStart ( previousNode , nextNode , currentSourceFile ) ; } } else { return ts . getStartsOnNewLine ( nextNode ) ; } } function shouldWriteClosingLineTerminator ( parentNode , children , format ) { if ( format & ts . ListFormat . MultiLine ) { return ( format & ts . ListFormat . NoTrailingNewLine ) === 0 ; } else if ( format & ts . ListFormat . PreserveLines ) { if ( format & ts . ListFormat . PreferNewLine ) { return true ; } const lastChild = ts . lastOrUndefined ( children ) ; if ( lastChild === undefined ) { return ! rangeIsOnSingleLine ( parentNode , currentSourceFile ) ; } else if ( positionIsSynthesized ( parentNode . pos ) || nodeIsSynthesized ( lastChild ) ) { return synthesizedNodeStartsOnNewLine ( lastChild , format ) ; } else { return ! rangeEndPositionsAreOnSameLine ( parentNode , lastChild , currentSourceFile ) ; } } else { return false ; } } function synthesizedNodeStartsOnNewLine ( node , format ) { if ( nodeIsSynthesized ( node ) ) { const startsOnNewLine = ts . getStartsOnNewLine ( node ) ; if ( startsOnNewLine === undefined ) { return ( format & ts . ListFormat . PreferNewLine ) !== 0 ; } return startsOnNewLine ; } return ( format & ts . ListFormat . PreferNewLine ) !== 0 ; } function needsIndentation ( parent , node1 , node2 ) { parent = skipSynthesizedParentheses ( parent ) ; node1 = skipSynthesizedParentheses ( node1 ) ; node2 = skipSynthesizedParentheses ( node2 ) ; return ! nodeIsSynthesized ( parent ) && ! nodeIsSynthesized ( node1 ) && ! nodeIsSynthesized ( node2 ) && ! rangeEndIsOnSameLineAsRangeStart ( node1 , node2 , currentSourceFile ) ; } function isEmptyBlock ( block ) { return block . statements . length === 0 && rangeEndIsOnSameLineAsRangeStart ( block , block , currentSourceFile ) ; } function skipSynthesizedParentheses ( node ) { while ( node . kind === SyntaxKind . ParenthesizedExpression && nodeIsSynthesized ( node ) ) { node = ( < ts . ParenthesizedExpression > node ) . expression ; } return node ; } function getTextOfNode ( node , includeTrivia ? ) { if ( isIdentifier ( node ) ) { const text = idText ( < ts . Identifier > node ) ; if ( text === 'undefined' ) { return 'null' ; } if ( shouldAddDollar ( node , state ) ) { return '$' + text ; } if ( shouldAddDoubleQuote ( node ) ) { return '"' + text . replace ( /(\\)?\$/g , '\\$' ) + '"' ; } return text ; } if ( isImportSpecifier ( node ) ) { return ( node . name . escapedText as string ) ; } return '' ; } function getLiteralTextOfNode ( node , neverAsciiEscape ) { return getLiteralText ( node , currentSourceFile , neverAsciiEscape ) ; } function getImportModuleName ( node ) { const moduleUri = node . moduleSpecifier . getText ( ) . replace ( /'|"/g , '' ) ; const isRelative = isRelativePath ( moduleUri ) ; let moduleName = moduleUri ; if ( ! isRelative ) { const arr = moduleUri . split ( '/' ) ; moduleName = arr [ 0 ] ; if ( moduleName [ 0 ] === '@' ) { moduleName += '/' ; moduleName += arr [ 1 ] ; } } const modulePath = moduleUri . replace ( moduleName , '' ) ; return { moduleName , modulePath } ; } /**
     * Push a new name generation scope.
     */ function pushNameGenerationScope ( node ) { if ( node && getEmitFlags ( node ) & ts . EmitFlags . ReuseTempVariableScope ) { return ; } tempFlagsStack . push ( tempFlags ) ; tempFlags = 0 ; reservedNamesStack . push ( reservedNames ) ; } /**
     * Pop the current name generation scope.
     */ function popNameGenerationScope ( node ) { if ( node && getEmitFlags ( node ) & ts . EmitFlags . ReuseTempVariableScope ) { return ; } tempFlags = tempFlagsStack . pop ( ) ! ; reservedNames = reservedNamesStack . pop ( ) ! ; } }