import assert from "assert" ; import * as types from "ast-types" ; const n = types . namedTypes ; import sourceMap from "source-map" ; const SourceMapConsumer = sourceMap . SourceMapConsumer ; const SourceMapGenerator = sourceMap . SourceMapGenerator ; const hasOwn = Object . prototype . hasOwnProperty ; export function getOption ( options , key , defaultValue ) { if ( options && hasOwn . call ( options , key ) ) { return options [ key ] ; } return defaultValue ; } export function getUnionOfKeys ( ... args ) { const result = { } ; const argc = args . length ; for ( let i = 0 ; i < argc ; ++ i ) { const keys = Object . keys ( args [ i ] ) ; const keyCount = keys . length ; for ( let j = 0 ; j < keyCount ; ++ j ) { result [ keys [ j ] ] = true ; } } return result ; } export function comparePos ( pos1 , pos2 ) { return pos1 . line - pos2 . line || pos1 . column - pos2 . column ; } export function copyPos ( pos ) { return { line : pos . line , column : pos . column , } ; } export function composeSourceMaps ( formerMap , latterMap ) { if ( formerMap ) { if ( ! latterMap ) { return formerMap ; } } else { return latterMap || null ; } const smcFormer = new SourceMapConsumer ( formerMap ) ; const smcLatter = new SourceMapConsumer ( latterMap ) ; const smg = new SourceMapGenerator ( { file : latterMap . file , sourceRoot : latterMap . sourceRoot , } ) ; const sourcesToContents = { } ; smcLatter . eachMapping ( function ( mapping ) { const origPos = smcFormer . originalPositionFor ( { line : mapping . originalLine , column : mapping . originalColumn , } ) ; const sourceName = origPos . source ; if ( sourceName === null ) { return ; } smg . addMapping ( { source : sourceName , original : copyPos ( origPos ) , generated : { line : mapping . generatedLine , column : mapping . generatedColumn , } , name : mapping . name , } ) ; const sourceContent = smcFormer . sourceContentFor ( sourceName ) ; if ( sourceContent && ! hasOwn . call ( sourcesToContents , sourceName ) ) { sourcesToContents [ sourceName ] = sourceContent ; smg . setSourceContent ( sourceName , sourceContent ) ; } } ) ; return ( smg as any ) . toJSON ( ) ; } export function getTrueLoc ( node , lines ) { if ( ! node . loc ) { return null ; } const result = { start : node . loc . start , end : node . loc . end , } ; function include ( node ) { expandLoc ( result , node . loc ) ; } if ( node . declaration && node . declaration . decorators && isExportDeclaration ( node ) ) { node . declaration . decorators . forEach ( include ) ; } if ( comparePos ( result . start , result . end ) < 0 ) { result . start = copyPos ( result . start ) ; lines . skipSpaces ( result . start , false , true ) ; if ( comparePos ( result . start , result . end ) < 0 ) { result . end = copyPos ( result . end ) ; lines . skipSpaces ( result . end , true , true ) ; } } if ( node . comments ) { node . comments . forEach ( include ) ; } return result ; } function expandLoc ( parentLoc , childLoc ) { if ( parentLoc && childLoc ) { if ( comparePos ( childLoc . start , parentLoc . start ) < 0 ) { parentLoc . start = childLoc . start ; } if ( comparePos ( parentLoc . end , childLoc . end ) < 0 ) { parentLoc . end = childLoc . end ; } } } export function fixFaultyLocations ( node , lines ) { const loc = node . loc ; if ( loc ) { if ( loc . start . line < 1 ) { loc . start . line = 1 ; } if ( loc . end . line < 1 ) { loc . end . line = 1 ; } } if ( node . type === "File" ) { loc . start = lines . firstPos ( ) ; loc . end = lines . lastPos ( ) ; } fixForLoopHead ( node , lines ) ; fixTemplateLiteral ( node , lines ) ; if ( loc && node . decorators ) { node . decorators . forEach ( function ( decorator ) { expandLoc ( loc , decorator . loc ) ; } ) ; } else if ( node . declaration && isExportDeclaration ( node ) ) { node . declaration . loc = null ; const decorators = node . declaration . decorators ; if ( decorators ) { decorators . forEach ( function ( decorator ) { expandLoc ( loc , decorator . loc ) ; } ) ; } } else if ( ( n . MethodDefinition && n . MethodDefinition . check ( node ) ) || ( n . Property . check ( node ) && ( node . method || node . shorthand ) ) ) { node . value . loc = null ; if ( n . FunctionExpression . check ( node . value ) ) { node . value . id = null ; } } else if ( node . type === "ObjectTypeProperty" ) { const loc = node . loc ; let end = loc && loc . end ; if ( end ) { end = copyPos ( end ) ; if ( lines . prevPos ( end ) && lines . charAt ( end ) === "," ) { if ( ( end = lines . skipSpaces ( end , true , true ) ) ) { loc . end = end ; } } } } } function fixForLoopHead ( node , lines ) { if ( node . type !== "ForStatement" ) { return ; } function fix ( child ) { const loc = child && child . loc ; const start = loc && loc . start ; const end = loc && copyPos ( loc . end ) ; while ( start && end && comparePos ( start , end ) < 0 ) { lines . prevPos ( end ) ; if ( lines . charAt ( end ) === ";" ) { loc . end . line = end . line ; loc . end . column = end . column ; } else { break ; } } } fix ( node . init ) ; fix ( node . test ) ; fix ( node . update ) ; } function fixTemplateLiteral ( node , lines ) { if ( node . type !== "TemplateLiteral" ) { return ; } if ( node . quasis . length === 0 ) { return ; } if ( node . loc ) { const afterLeftBackTickPos = copyPos ( node . loc . start ) ; assert . strictEqual ( lines . charAt ( afterLeftBackTickPos ) , "`" ) ; assert . ok ( lines . nextPos ( afterLeftBackTickPos ) ) ; const firstQuasi = node . quasis [ 0 ] ; if ( comparePos ( firstQuasi . loc . start , afterLeftBackTickPos ) < 0 ) { firstQuasi . loc . start = afterLeftBackTickPos ; } const rightBackTickPos = copyPos ( node . loc . end ) ; assert . ok ( lines . prevPos ( rightBackTickPos ) ) ; assert . strictEqual ( lines . charAt ( rightBackTickPos ) , "`" ) ; const lastQuasi = node . quasis [ node . quasis . length - 1 ] ; if ( comparePos ( rightBackTickPos , lastQuasi . loc . end ) < 0 ) { lastQuasi . loc . end = rightBackTickPos ; } } node . expressions . forEach ( function ( expr , i ) { const dollarCurlyPos = lines . skipSpaces ( expr . loc . start , true , false ) ; if ( lines . prevPos ( dollarCurlyPos ) && lines . charAt ( dollarCurlyPos ) === "{" && lines . prevPos ( dollarCurlyPos ) && lines . charAt ( dollarCurlyPos ) === "$" ) { const quasiBefore = node . quasis [ i ] ; if ( comparePos ( dollarCurlyPos , quasiBefore . loc . end ) < 0 ) { quasiBefore . loc . end = dollarCurlyPos ; } } const rightCurlyPos = lines . skipSpaces ( expr . loc . end , false , false ) ; if ( lines . charAt ( rightCurlyPos ) === "}" ) { assert . ok ( lines . nextPos ( rightCurlyPos ) ) ; const quasiAfter = node . quasis [ i + 1 ] ; if ( comparePos ( quasiAfter . loc . start , rightCurlyPos ) < 0 ) { quasiAfter . loc . start = rightCurlyPos ; } } } ) ; } export function isExportDeclaration ( node ) { if ( node ) switch ( node . type ) { case "ExportDeclaration" : case "ExportDefaultDeclaration" : case "ExportDefaultSpecifier" : case "DeclareExportDeclaration" : case "ExportNamedDeclaration" : case "ExportAllDeclaration" : return true ; } return false ; } export function getParentExportDeclaration ( path ) { const parentNode = path . getParentNode ( ) ; if ( path . getName ( ) === "declaration" && isExportDeclaration ( parentNode ) ) { return parentNode ; } return null ; } export function isTrailingCommaEnabled ( options , context ) { const trailingComma = options . trailingComma ; if ( typeof trailingComma === "object" ) { return ! ! trailingComma [ context ] ; } return ! ! trailingComma ; }