question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`parse()` with `inputSourceMap` option

See original GitHub issue

Bug Report

  • I would like to work on a fix!

Current behavior

Files:

  • 2 x source files a.js + b.js
  • Both files transpiled with Babel to a.intermediate.js + b.intermediate.js with source maps

I am trying to parse the two intermediate files and combine them into a new file with a source map referencing the original source files.

parse() with inputSourceMap option does not seem to pick up the source maps. This applies whether source maps are inline or provided explicitly to parse() with inputSourceMap option.

Code example below is also at: https://github.com/overlookmotel/babel-parse-source-maps-case

Input Code

const {parse} = require('@babel/parser'),
  generate = require('@babel/generator').default,
  {SourceMapConsumer} = require('source-map'), // v0.5.7
  t = require('@babel/types');

// Original files
const inputA = 'var x = 1;';
const inputB = 'var y = 2;';

// Create intermediates
const astA = parse( inputA, { sourceFilename: 'a.js' } );
astA.program.body.unshift( t.variableDeclaration( 'var', [ t.variableDeclarator( t.identifier('q') ) ] ) );
const { code: codeA, map: mapA } = generate(
  astA,
  {sourceMaps: true, sourceFileName: 'a.js'},
  inputA
);

const astB = parse( inputB, { sourceFilename: 'b.js' } );
astB.program.body.unshift( t.variableDeclaration( 'var', [ t.variableDeclarator( t.identifier('r') ) ] ) );
const { code: codeB, map: mapB } = generate(
  astB,
  { sourceMaps: true, sourceFileName: 'b.js' },
  inputB
);

// Parse intermediates
const ast2A = parse( codeA, { sourceFilename: 'a.intermediate.js', inputSourceMap: mapA } );
const ast2B = parse( codeB, { sourceFilename: 'b.intermediate.js', inputSourceMap: mapB } );

// Combine the two
const astCombined = t.program(
  [ ...ast2A.program.body, ...ast2B.program.body ]
);

const { code: codeCombined, map: mapCombined } = generate(
  astCombined,
  { sourceMaps: true },
  {
    'a.intermediate.js': codeA,
    'b.intermediate.js': codeB,
    'a.js': inputA,
    'b.js': inputB
  }
);

console.log( 'codeCombined:', JSON.stringify( codeCombined ) );
console.log( 'mapCombined:', mapCombined );

const consumer = new SourceMapConsumer( mapCombined );
console.log( 'posX:', consumer.originalPositionFor( { line: 2, column: 4 } ) );
console.log( 'posY:', consumer.originalPositionFor( { line: 4, column: 4 } ) );

Expected behavior

Expected source map to reference the original source files, not the intermediate files.

Output of above script is:

codeCombined: "var q;\nvar x = 1;\nvar r;\nvar y = 2;"
mapCombined: {
  version: 3,
  sources: [ 'a.intermediate.js', 'b.intermediate.js' ],
  names: [ 'q', 'x', 'r', 'y' ],
  mappings: 'AAAA,IAAIA,CAAJ;AACA,IAAIC,CAAC,GAAG,CAAR;ACDA,IAAIC,CAAJ;AACA,IAAIC,CAAC,GAAG,CAAR',
  sourcesContent: [ 'var q;\nvar x = 1;', 'var r;\nvar y = 2;' ]
}
posX: { source: 'a.intermediate.js', line: 2, column: 4, name: 'x' }
posY: { source: 'b.intermediate.js', line: 2, column: 4, name: 'y' }

Babel Configuration (babel.config.js, .babelrc, package.json#babel, cli command, .eslintrc)

(none)

Environment

System:
  OS: macOS Mojave 10.14.6
Binaries:
  Node: 14.7.0 - ~/.nvm/versions/node/v14.7.0/bin/node
  npm: 6.14.7 - ~/.nvm/versions/node/v14.7.0/bin/npm
npmPackages:
  @babel/generator: ^7.11.0 => 7.11.0 
  @babel/parser: ^7.11.3 => 7.11.3 
  @babel/types: ^7.11.0 => 7.11.0

Possible Solution

No idea!

Additional context

Is the inputSourceMap option supported by parse()?

If not, is there another way to achieve what I’m trying to do?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:9 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
mischniccommented, Dec 8, 2020

To actually support this, @babel/parser would have to do something like

node.loc = this.inputSourceMap.originalPositionFor(this.state.currentPosition)

instead of

node.loc = this.state.currentPosition

This is probably much slower than merging the sourcemaps after the fact yourself…

0reactions
mischniccommented, Dec 9, 2020

At least this step:

const astCombined = t.program(
  [ ...ast2A.program.body, ...ast2B.program.body ]
);

should be equivalent to adding the sourcemap of the second file to the first one with an offset of lineCount(sourceA). I couldn’t find any other library that supports this easily so I’ll have to plug a library I’ve also worked on: https://v2.parceljs.org/plugin-system/source-maps/#%40parcel%2Fsource-maps%3A-api (the lineOffset parameter). We do exactly this when generating JS bundles (by concatenating the individual JS files) in Parcel.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Options - Babel.js
When passed directly to Babel, you can just pass the options object. ... Specifying cloneInputAst: false can improve parsing performance if the input...
Read more >
PostCSS API
Parses source css and returns a new Root or Document node, which contains the source CSS nodes. // Simple CSS concatenation with source...
Read more >
Grunt babel multiple files and preserve source mapping
Babel will always parse the source map comment from concat output, as long as inputSourceMap is truthy. Even worse, it will ignore any...
Read more >
How to use the babel-core.version function in babel-core - Snyk
parseQuery (this.query); var userOptions = assign({}, globalOptions, loaderOptions); var defaultOptions = { metadataSubscribers: [], inputSourceMap: ...
Read more >
UglifyJS 3 - JavaScript on Fiber - FIBJS
-p, --parse <options> Specify parser options: `acorn` Use Acorn for parsing. ... `content` Input source map, useful if you're compressing JS that was ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found