file author meixuguang
  import * as ts from 'byots' ; import { error } from './state' ; import { isClassInstance , isClassLike , isFunctionLike } from './utilities/nodeTest' ; const indentStrings = [ '' , '    ' ] ; export function getIndentString ( level ) { if ( indentStrings [ level ] === undefined ) { indentStrings [ level ] = getIndentString ( level - 1 ) + indentStrings [ 1 ] ; } return indentStrings [ level ] ; } export function getIndentSize ( ) { return indentStrings [ 1 ] . length ; } export function showSymbol ( symbol ) { const symbolFlags = ts . SymbolFlags ; return `{ flags: ${ symbolFlags ? showFlags ( symbol . flags , symbolFlags ) : symbol . flags }; declarations: ${ ts . map ( symbol . declarations , showSyntaxKind ) } }` ; } function showFlags ( flags , flagsEnum ) { const out = [ ] ; for ( let pow = 0 ; pow <= 30 ; pow ++ ) { const n = 1 << pow ; if ( flags & n ) { out . push ( flagsEnum [ n ] ) ; } } return out . join ( '|' ) ; } export function showSyntaxKind ( node ) { const syntaxKind = ts . SyntaxKind ; return syntaxKind ? syntaxKind [ node . kind ] : node . kind . toString ( ) ; } /**
 * Gets flags that control emit behavior of a node.
 */ export function getEmitFlags ( node ) { const emitNode = node . emitNode ; return emitNode && emitNode . flags || 0 ; } export function getLiteralText ( node , sourceFile , neverAsciiEscape ) { const escapeText = neverAsciiEscape || ( getEmitFlags ( node ) & ts . EmitFlags . NoAsciiEscaping ) ? escapeString : escapeNonAsciiString ; switch ( node . kind ) { case ts . SyntaxKind . StringLiteral : if ( ( < ts . StringLiteral > node ) . singleQuote ) { return "'" + escapeText ( node . text , ts . CharacterCodes . singleQuote ) + "'" ; } else { return '"' + escapeText ( node . text , ts . CharacterCodes . doubleQuote ) + '"' ; } case ts . SyntaxKind . NoSubstitutionTemplateLiteral : return '"' + escapeText ( node . text , ts . CharacterCodes . doubleQuote ) + '"' ; case ts . SyntaxKind . TemplateHead : return '"' + escapeText ( node . text , ts . CharacterCodes . doubleQuote ) + '" ' + '.' ; case ts . SyntaxKind . TemplateMiddle : return ' . "' + escapeText ( node . text , ts . CharacterCodes . doubleQuote ) + '" .' ; case ts . SyntaxKind . TemplateTail : const text = escapeText ( node . text , ts . CharacterCodes . doubleQuote ) ; if ( text ) { return ' . "' + text + '"' ; } return '' ; case ts . SyntaxKind . NumericLiteral : case ts . SyntaxKind . RegularExpressionLiteral : return node . text ; } error ( ts . createDiagnosticForNodeInSourceFile ( sourceFile , node , { category : ts . DiagnosticCategory . Error , message : `Literal kind '${ node . kind }' not accounted for.` , code : 5555 , key : 'ts2php' } ) ) ; return '' ; } export function nodeIsSynthesized ( range ) { return positionIsSynthesized ( range . pos ) || positionIsSynthesized ( range . end ) ; } export function positionIsSynthesized ( pos ) { return ! ( pos >= 0 ) ; } export function idText ( identifier ) { return unescapeLeadingUnderscores ( identifier . escapedText ) ; } export function rangeIsOnSingleLine ( range , sourceFile ) { return rangeStartIsOnSameLineAsRangeEnd ( range , range , sourceFile ) ; } export function rangeEndPositionsAreOnSameLine ( range1 , range2 , sourceFile ) { return positionsAreOnSameLine ( range1 . end , range2 . end , sourceFile ) ; } export function rangeStartIsOnSameLineAsRangeEnd ( range1 , range2 , sourceFile ) { return positionsAreOnSameLine ( getStartPositionOfRange ( range1 , sourceFile ) , range2 . end , sourceFile ) ; } param identifier returns export function unescapeLeadingUnderscores ( identifier ) { const id = identifier as string ; return id . length >= 3 && id . charCodeAt ( 0 ) === ts . CharacterCodes . _ && id . charCodeAt ( 1 ) === ts . CharacterCodes . _ && id . charCodeAt ( 2 ) === ts . CharacterCodes . _ ? id . substr ( 1 ) : id ; } export function rangeStartPositionsAreOnSameLine ( range1 , range2 , sourceFile ) { return positionsAreOnSameLine ( getStartPositionOfRange ( range1 , sourceFile ) , getStartPositionOfRange ( range2 , sourceFile ) , sourceFile ) ; } export function positionsAreOnSameLine ( pos1 , pos2 , sourceFile ) { return pos1 === pos2 || getLineOfLocalPosition ( sourceFile , pos1 ) === getLineOfLocalPosition ( sourceFile , pos2 ) ; } export function rangeEndIsOnSameLineAsRangeStart ( range1 , range2 , sourceFile ) { return positionsAreOnSameLine ( range1 . end , getStartPositionOfRange ( range2 , sourceFile ) , sourceFile ) ; } export function getLineOfLocalPosition ( currentSourceFile , pos ) { return ts . getLineAndCharacterOfPosition ( currentSourceFile , pos ) . line ; } export function getStartPositionOfRange ( range , sourceFile ) { return positionIsSynthesized ( range . pos ) ? - 1 : ts . skipTrivia ( sourceFile . text , range . pos ) ; } export function isGeneratedIdentifier ( node ) { return isIdentifier ( node ) && ( ( < ts . Identifier > node ) . autoGenerateFlags ! & ts . GeneratedIdentifierFlags . KindMask ) > ts . GeneratedIdentifierFlags . None ; } export function isIdentifier ( node ) { return node . kind === ts . SyntaxKind . Identifier ; } export function isBindingPattern ( node ) { if ( node ) { const kind = node . kind ; return kind === ts . SyntaxKind . ArrayBindingPattern || kind === ts . SyntaxKind . ObjectBindingPattern ; } return false ; } export function isNodeDescendantOf ( node , ancestor ) { while ( node ) { if ( node === ancestor ) return true ; node = node . parent ; } return false ; } export function isAssignmentPattern ( node ) { const kind = node . kind ; return kind === ts . SyntaxKind . ArrayLiteralExpression || kind === ts . SyntaxKind . ObjectLiteralExpression ; } export function isArrayBindingElement ( node ) { const kind = node . kind ; return kind === ts . SyntaxKind . BindingElement || kind === ts . SyntaxKind . OmittedExpression ; } export function isPrologueDirective ( node ) { return node . kind === ts . SyntaxKind . ExpressionStatement && ( < ts . ExpressionStatement > node ) . expression . kind === ts . SyntaxKind . StringLiteral ; } export function nodeIsMissing ( node ) { if ( node === undefined ) { return true ; } return node . pos === node . end && node . pos >= 0 && node . kind !== ts . SyntaxKind . EndOfFileToken ; } /**
 * Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
 * but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine)
 * Note that this doesn't actually wrap the input in double quotes.
 */ export function escapeString ( s , quoteChar ? ) { const escapedCharsRegExp = quoteChar === ts . CharacterCodes . backtick ? backtickQuoteEscapedCharsRegExp : quoteChar === ts . CharacterCodes . singleQuote ? singleQuoteEscapedCharsRegExp : doubleQuoteEscapedCharsRegExp ; return s . replace ( escapedCharsRegExp , getReplacement ) ; } function getReplacement ( c , offset , input ) { if ( c . charCodeAt ( 0 ) === ts . CharacterCodes . nullCharacter ) { const lookAhead = input . charCodeAt ( offset + c . length ) ; if ( lookAhead >= ts . CharacterCodes . _0 && lookAhead <= ts . CharacterCodes . _9 ) { return '\\x00' ; } return '\\0' ; } return escapedCharsMap . get ( c ) || get16BitUnicodeEscapeSequence ( c . charCodeAt ( 0 ) ) ; } function get16BitUnicodeEscapeSequence ( charCode ) { const hexCharCode = charCode . toString ( 16 ) . toUpperCase ( ) ; const paddedHexCode = ( '0000' + hexCharCode ) . slice ( - 4 ) ; return '\\u' + paddedHexCode ; } const doubleQuoteEscapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g ; const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g ; const backtickQuoteEscapedCharsRegExp = /[\\\`\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g ; const escapedCharsMap = ts . createMapFromTemplate ( { '\t' : '\\t' , '\v' : '\\v' , '\f' : '\\f' , '\b' : '\\b' , '\r' : '\\r' , '\n' : '\\n' , '\\' : '\\\\' , '"' : '\\"' , "\'" : "\\\'" , '\`' : '\\\`' , '\u2028' : '\\u2028' , '\u2029' : '\\u2029' , '\u0085' : '\\u0085' } ) ; const nonAsciiCharacters = /[^\u0000-\u007F]/g ; export function escapeNonAsciiString ( s , quoteChar ? ) { s = escapeString ( s , quoteChar ) ; return nonAsciiCharacters . test ( s ) ? s . replace ( nonAsciiCharacters , c => get16BitUnicodeEscapeSequence ( c . charCodeAt ( 0 ) ) ) : s ; } /**
 * Returns a value indicating whether a name is unique globally or within the current file.
 * Note: This does not consider whether a name appears as a free identifier or not, so at the expression `x.y` this includes both `x` and `y`.
 */ export function isFileLevelUniqueName ( sourceFile , name , hasGlobalName ? ) { return ! ( hasGlobalName && hasGlobalName ( name ) ) && ! sourceFile . identifiers . has ( name ) ; } export function getLastExpression ( node ) { let exp = node as ts . PropertyAccessExpression ; do { exp = exp . expression as ts . PropertyAccessExpression ; } while ( exp . expression ) ; return exp ; } export function getDescendantIdentifiers ( node ) { const identifiers = [ ] ; const stack = [ node ] ; while ( stack . length > 0 ) { const cur = stack . pop ( ) ; cur . forEachChild ( child => { if ( child . kind === ts . SyntaxKind . Identifier ) { if ( ! child . parent || ! ts . isTypeNode ( child . parent ) ) { identifiers . push ( child as ts . Identifier ) ; } } else { stack . push ( child ) ; } } ) ; } return identifiers ; } /**
 * in case expression is wrapped by Parenthesis
 */ export function getRealExpression ( node ) { while ( node . kind === ts . SyntaxKind . ParenthesizedExpression ) { node = ( node as ts . ParenthesizedExpression ) . expression ; } return node ; } export function getAccessPrefixAndSuffix ( node , typeChecker ) { let prefix = '[' ; let suffix = ']' ; if ( ts . isPropertyAccessExpression ( node ) ) { prefix = '["' ; suffix = '"]' ; } const expression = getRealExpression ( node . expression ) ; if ( expression . kind === ts . SyntaxKind . ThisKeyword || isClassInstance ( expression , typeChecker ) || expression . kind === ts . SyntaxKind . NewExpression ) { prefix = '->' ; suffix = '' ; } else if ( isClassLike ( node . expression , typeChecker ) ) { const isMethod = isFunctionLike ( node , typeChecker ) ; if ( isMethod ) { prefix = '::' ; suffix = '' ; } else { prefix = '::$' ; suffix = '' ; } if ( ! ts . isPropertyAccessExpression ( node ) && ts . isLiteralExpression ( node . argumentExpression ) ) { node . argumentExpression . kind = ts . SyntaxKind . NumericLiteral ; } } return { prefix , suffix } ; }