import assert from "assert" ; import sourceMap from "source-map" ; import * as recast from "../main" ; import * as types from "ast-types" ; const n = types . namedTypes ; const b = types . builders ; const NodePath = types . NodePath ; import { fromString } from "../lib/lines" ; import { parse } from "../lib/parser" ; import { Printer } from "../lib/printer" ; import { EOL as eol } from "os" ; describe ( "source maps" , function ( ) { it ( "should generate correct mappings" , function ( ) { const code = [ "function foo(bar) {" , "  return 1 + bar;" , "}" ] . join ( eol ) ; fromString ( code ) ; const ast = parse ( code , { sourceFileName : "source.js" , } ) ; const path = new NodePath ( ast ) ; const returnPath = path . get ( "program" , "body" , 0 , "body" , "body" , 0 ) ; n . ReturnStatement . assert ( returnPath . value ) ; const leftPath = returnPath . get ( "argument" , "left" ) ; const leftValue = leftPath . value ; const rightPath = returnPath . get ( "argument" , "right" ) ; leftPath . replace ( rightPath . value ) ; rightPath . replace ( leftValue ) ; const sourceRoot = "path/to/source/root" ; const printed = new Printer ( { sourceMapName : "source.map.json" , sourceRoot : sourceRoot , } ) . print ( ast ) ; assert . ok ( printed . map ) ; assert . strictEqual ( printed . map . file , "source.map.json" ) ; assert . strictEqual ( printed . map . sourceRoot , sourceRoot ) ; const smc = new sourceMap . SourceMapConsumer ( printed . map ) ; function check ( origLine , origCol , genLine , genCol , lastColumn ) { assert . deepEqual ( smc . originalPositionFor ( { line : genLine , column : genCol , } ) , { source : sourceRoot + "/source.js" , line : origLine , column : origCol , name : null , } ) ; assert . deepEqual ( smc . generatedPositionFor ( { source : sourceRoot + "/source.js" , line : origLine , column : origCol , } ) , { line : genLine , column : genCol , lastColumn : lastColumn , } ) ; } check ( 1 , 0 , 1 , 0 , null ) ; check ( 1 , 18 , 1 , 18 , null ) ; check ( 2 , 13 , 2 , 9 , null ) ; check ( 2 , 9 , 2 , 15 , null ) ; check ( 3 , 0 , 3 , 0 , null ) ; } ) ; it ( "should compose with inputSourceMap" , function ( ) { function addUseStrict ( ast ) { return recast . visit ( ast , { visitFunction : function ( path ) { path . get ( "body" , "body" ) . unshift ( b . expressionStatement ( b . literal ( "use strict" ) ) ) ; this . traverse ( path ) ; } , } ) ; } function stripConsole ( ast ) { return recast . visit ( ast , { visitCallExpression : function ( path ) { const node = path . value ; if ( n . MemberExpression . check ( node . callee ) && n . Identifier . check ( node . callee . object ) && node . callee . object . name === "console" ) { n . ExpressionStatement . assert ( path . parent . node ) ; path . parent . replace ( ) ; return false ; } return ; } , } ) ; } const code = [ "function add(a, b) {" , "  var sum = a + b;" , "  console.log(a, b);" , "  return sum;" , "}" , ] . join ( eol ) ; const ast = parse ( code , { sourceFileName : "original.js" , } ) ; const useStrictResult = new Printer ( { sourceMapName : "useStrict.map.json" , } ) . print ( addUseStrict ( ast ) ) ; const useStrictAst = parse ( useStrictResult . code , { sourceFileName : "useStrict.js" , } ) ; const oneStepResult = new Printer ( { sourceMapName : "oneStep.map.json" , } ) . print ( stripConsole ( ast ) ) ; const twoStepResult = new Printer ( { sourceMapName : "twoStep.map.json" , inputSourceMap : useStrictResult . map , } ) . print ( stripConsole ( useStrictAst ) ) ; assert . strictEqual ( oneStepResult . code , twoStepResult . code ) ; const smc1 = new sourceMap . SourceMapConsumer ( oneStepResult . map ) ; const smc2 = new sourceMap . SourceMapConsumer ( twoStepResult . map ) ; smc1 . eachMapping ( function ( mapping ) { const pos = { line : mapping . generatedLine , column : mapping . generatedColumn , } ; const orig1 = smc1 . originalPositionFor ( pos ) ; const orig2 = smc2 . originalPositionFor ( pos ) ; assert . deepEqual ( orig1 , orig2 ) ; assert . strictEqual ( orig2 . source , "original.js" ) ; } ) ; } ) ; it ( "should work when a child node becomes null" , function ( ) { const code = [ "for (var i = 0; false; i++)" , "  log(i);" ] . join ( eol ) ; const ast = parse ( code ) ; const path = new NodePath ( ast ) ; const updatePath = path . get ( "program" , "body" , 0 , "update" ) ; n . UpdateExpression . assert ( updatePath . value ) ; updatePath . replace ( null ) ; const printed = new Printer ( ) . print ( ast ) ; assert . strictEqual ( printed . code , [ "for (var i = 0; false; )" , "  log(i);" ] . join ( eol ) ) ; } ) ; it ( "should tolerate programs that become empty" , function ( ) { const source = "foo();" ; const ast = recast . parse ( source , { sourceFileName : "foo.js" , } ) ; assert . strictEqual ( ast . program . body . length , 1 ) ; ast . program . body . length = 0 ; const result = recast . print ( ast , { sourceMapName : "foo.map.json" , } ) ; assert . strictEqual ( result . map . file , "foo.map.json" ) ; assert . deepEqual ( result . map . sources , [ ] ) ; assert . deepEqual ( result . map . names , [ ] ) ; assert . strictEqual ( result . map . mappings , "" ) ; } ) ; } ) ;