microsoft / microsoft/vscode-js-debug

Breakpoints in anonymous functions are sometimes disabled in a transpiled language using source maps

Open
#2,250 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2k
Forks
373
Avg merge
1d 9m
Merged PRs (30d)
6

Description

This is a bit of an esoteric use-case, but I would still very much like to solve it,
since it hampers development in my language: SmallJS ( https://github.com/Small-JS/SmallJS ).
This issue is perhaps for someone with a deeper knowledge of SourceMaps in VSCode.

SmallJS is a Smalltalk (ST) dialect that transpiles to JavaScript (JS).
Using SourceMaps I can succesfully debug the ST source code that is executing in JS.
For every ST function call (message send), a positioned SourceNode is generated
with line and column number, so VSCode can halt on set breakpoints and inspect variables.
In most cases this works great.

ST also has the concept of anonymous functions, called blocks, with square brackets [ ],
that are transpiled directly to their JS equivalents.

Now the problem:
In some case, on starting debugging, VSCode disables (unbinds) breakpoints set within these blocks.
and the code will execute without the debugger being activated.
Below is an ST code fragment wth 2 log statements, each within an anonymous function, with a breakpoint set.

  • In the 1st example "log: 'h1'" the breakpoint is kept after starting and it works correctly.
  • In the 2nd example "log: 'h2'" the breakpoint is removed (greyed out, unbound) after starting and does not work.
    And I'm quite certain the SourceNodes for the SourceMap are generated correctly, the same as for the 1st,
    And the console also logs 'h2', so the function is called.
  • Below the ST code is the transpiled JS code, where breakpoints work correctly on both examples
    when set directly in JS on the log statements.

So the question is how to get the breakpoint in case 2 to work correctly.
(BTW a very common use-case in Smalltalk).

Any help is greatly appreciated.
Cheers,
Richard

--

Screenshot:
Image

ST code:

myTest
	"Setting a breakpoint within this block on the log statement works:"
	| block |
	block := [
		self log: 'h1' ].
	block value.     "Executes the anonymous function"

	"... but setting a breakpoint this log statement does *not* work."
	true ifTrue: [
		self log: 'h2' ].
!

Tanspiled JS code: (breakpoints work normally)

	$myTest()
	{
		let block = stNil;
		block = stBlock$class.$fromJs$( (  ) => {
				return this.$log$( stString$class.$fromJs$( 'h1' ) );
			} );
		block.$value();
		stTrue.$ifTrue$( stBlock$class.$fromJs$( (  ) => {
				return this.$log$( stString$class.$fromJs$( 'h2' ) );
			} ) );
		return this;
	}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the breakpoint behavior with the SmallJS ST fragment and the transpiled JavaScript shown in the issue. Inspect how the debugger binds source-mapped breakpoints inside the two anonymous functions, comparing the working block value case with the failing ifTrue case. Done means the second source-level breakpoint remains bound and pauses execution.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript, vscode
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.