import * as ts from 'typescript' ; import NestedError = require ( 'nested-error-stacks' ) ; import { PartialVisitorContext } from './visitor-context' ; import { transformNode } from './transform-node' ; function getFunctionBehavior ( options ? ) { if ( options ) { if ( options . functionBehavior ) { if ( options . functionBehavior === 'ignore' || options . functionBehavior === 'basic' ) { return options . functionBehavior ; } } else { if ( ! ! options . ignoreFunctions ) { return 'ignore' ; } } } return 'error' ; } function getEmitDetailedErrors ( options ? ) { if ( options ) { if ( options . emitDetailedErrors === 'auto' || typeof options . emitDetailedErrors === 'boolean' ) { return options . emitDetailedErrors ; } } return 'auto' ; } export default function transformer ( program , options ? ) { if ( options && options . verbose ) { console . log ( `typescript-is: transforming program with ${ program . getSourceFiles ( ) . length } source files; using TypeScript ${ ts . version }.` ) ; } const visitorContext = { program , checker : program . getTypeChecker ( ) , compilerOptions : program . getCompilerOptions ( ) , options : { shortCircuit : ! ! ( options && options . shortCircuit ) , ignoreClasses : ! ! ( options && options . ignoreClasses ) , ignoreMethods : ! ! ( options && options . ignoreMethods ) , functionBehavior : getFunctionBehavior ( options ) , disallowSuperfluousObjectProperties : ! ! ( options && options . disallowSuperfluousObjectProperties ) , transformNonNullExpressions : ! ! ( options && options . transformNonNullExpressions ) , emitDetailedErrors : getEmitDetailedErrors ( options ) } , typeMapperStack : [ ] , previousTypeReference : null } ; return ( context ) => ( file ) => transformNodeAndChildren ( file , program , context , visitorContext ) ; } function transformNodeAndChildren ( node , program , context , visitorContext ) ; function transformNodeAndChildren ( node , program , context , visitorContext ) ; function transformNodeAndChildren ( node , program , context , visitorContext ) { let transformedNode ; try { transformedNode = transformNode ( node , visitorContext ) ; } catch ( error ) { const sourceFile = node . getSourceFile ( ) ; const { line , character } = sourceFile . getLineAndCharacterOfPosition ( node . pos ) ; throw new NestedError ( `Failed to transform node at: ${ sourceFile . fileName }:${ line + 1 }:${ character + 1 }` , error ) ; } return ts . visitEachChild ( transformedNode , ( childNode ) => transformNodeAndChildren ( childNode , program , context , visitorContext ) , context ) ; }