import assert from "assert" ; import { comparePos } from "./util" ; import { namedTypes } from "ast-types" ; import { Lines } from "./lines" ; type Pos = namedTypes . Position ; type Loc = namedTypes . SourceLocation ; export default class Mapping { constructor ( public sourceLines , public sourceLoc , public targetLoc = sourceLoc ) { } slice ( lines , start , end = lines . lastPos ( ) ) { const sourceLines = this . sourceLines ; let sourceLoc = this . sourceLoc ; let targetLoc = this . targetLoc ; function skip ( name ) { const sourceFromPos = sourceLoc [ name ] ; const targetFromPos = targetLoc [ name ] ; let targetToPos = start ; if ( name === "end" ) { targetToPos = end ; } else { assert . strictEqual ( name , "start" ) ; } return skipChars ( sourceLines , sourceFromPos , lines , targetFromPos , targetToPos ) ; } if ( comparePos ( start , targetLoc . start ) <= 0 ) { if ( comparePos ( targetLoc . end , end ) <= 0 ) { targetLoc = { start : subtractPos ( targetLoc . start , start . line , start . column ) , end : subtractPos ( targetLoc . end , start . line , start . column ) , } ; } else if ( comparePos ( end , targetLoc . start ) <= 0 ) { return null ; } else { sourceLoc = { start : sourceLoc . start , end : skip ( "end" ) , } ; targetLoc = { start : subtractPos ( targetLoc . start , start . line , start . column ) , end : subtractPos ( end , start . line , start . column ) , } ; } } else { if ( comparePos ( targetLoc . end , start ) <= 0 ) { return null ; } if ( comparePos ( targetLoc . end , end ) <= 0 ) { sourceLoc = { start : skip ( "start" ) , end : sourceLoc . end , } ; targetLoc = { start : { line : 1 , column : 0 } , end : subtractPos ( targetLoc . end , start . line , start . column ) , } ; } else { sourceLoc = { start : skip ( "start" ) , end : skip ( "end" ) , } ; targetLoc = { start : { line : 1 , column : 0 } , end : subtractPos ( end , start . line , start . column ) , } ; } } return new Mapping ( this . sourceLines , sourceLoc , targetLoc ) ; } add ( line , column ) { return new Mapping ( this . sourceLines , this . sourceLoc , { start : addPos ( this . targetLoc . start , line , column ) , end : addPos ( this . targetLoc . end , line , column ) , } ) ; } subtract ( line , column ) { return new Mapping ( this . sourceLines , this . sourceLoc , { start : subtractPos ( this . targetLoc . start , line , column ) , end : subtractPos ( this . targetLoc . end , line , column ) , } ) ; } indent ( by , skipFirstLine = false , noNegativeColumns = false ) { if ( by === 0 ) { return this ; } let targetLoc = this . targetLoc ; const startLine = targetLoc . start . line ; const endLine = targetLoc . end . line ; if ( skipFirstLine && startLine === 1 && endLine === 1 ) { return this ; } targetLoc = { start : targetLoc . start , end : targetLoc . end , } ; if ( ! skipFirstLine || startLine > 1 ) { const startColumn = targetLoc . start . column + by ; targetLoc . start = { line : startLine , column : noNegativeColumns ? Math . max ( 0 , startColumn ) : startColumn , } ; } if ( ! skipFirstLine || endLine > 1 ) { const endColumn = targetLoc . end . column + by ; targetLoc . end = { line : endLine , column : noNegativeColumns ? Math . max ( 0 , endColumn ) : endColumn , } ; } return new Mapping ( this . sourceLines , this . sourceLoc , targetLoc ) ; } } function addPos ( toPos , line , column ) { return { line : toPos . line + line - 1 , column : toPos . line === 1 ? toPos . column + column : toPos . column , } ; } function subtractPos ( fromPos , line , column ) { return { line : fromPos . line - line + 1 , column : fromPos . line === line ? fromPos . column - column : fromPos . column , } ; } function skipChars ( sourceLines , sourceFromPos , targetLines , targetFromPos , targetToPos ) { const targetComparison = comparePos ( targetFromPos , targetToPos ) ; if ( targetComparison === 0 ) { return sourceFromPos ; } let sourceCursor , targetCursor ; if ( targetComparison < 0 ) { sourceCursor = sourceLines . skipSpaces ( sourceFromPos ) || sourceLines . lastPos ( ) ; targetCursor = targetLines . skipSpaces ( targetFromPos ) || targetLines . lastPos ( ) ; const lineDiff = targetToPos . line - targetCursor . line ; sourceCursor . line += lineDiff ; targetCursor . line += lineDiff ; if ( lineDiff > 0 ) { sourceCursor . column = 0 ; targetCursor . column = 0 ; } else { assert . strictEqual ( lineDiff , 0 ) ; } while ( comparePos ( targetCursor , targetToPos ) < 0 && targetLines . nextPos ( targetCursor , true ) ) { assert . ok ( sourceLines . nextPos ( sourceCursor , true ) ) ; assert . strictEqual ( sourceLines . charAt ( sourceCursor ) , targetLines . charAt ( targetCursor ) ) ; } } else { sourceCursor = sourceLines . skipSpaces ( sourceFromPos , true ) || sourceLines . firstPos ( ) ; targetCursor = targetLines . skipSpaces ( targetFromPos , true ) || targetLines . firstPos ( ) ; const lineDiff = targetToPos . line - targetCursor . line ; sourceCursor . line += lineDiff ; targetCursor . line += lineDiff ; if ( lineDiff < 0 ) { sourceCursor . column = sourceLines . getLineLength ( sourceCursor . line ) ; targetCursor . column = targetLines . getLineLength ( targetCursor . line ) ; } else { assert . strictEqual ( lineDiff , 0 ) ; } while ( comparePos ( targetToPos , targetCursor ) < 0 && targetLines . prevPos ( targetCursor , true ) ) { assert . ok ( sourceLines . prevPos ( sourceCursor , true ) ) ; assert . strictEqual ( sourceLines . charAt ( sourceCursor ) , targetLines . charAt ( targetCursor ) ) ; } } return sourceCursor ; }