Refactor JS sourcemap generator (#21053)
* Parse the new line format * Fix pattern Didn't have space after the path * Remove duplicate sources Sources would sometimes double up with a new line at the end * Remove unused variable * Refactor sourcemap.nim Removes the multiple translations needed, now goes from single high level type to the final SourceMap Adds documentation for procs * Line numbers line up properly now Files aren't linking correctly though * Files now link up correctly Lines are sometimes off but overall seems pretty good Just need to implement parser * Add column info to output Add sourceMappingURL to rope directly to prevent copy * Properly handle columns * Remove debug lines * Add testcase * Finish testcase * Use the outdir folder instead of the folder the test is in to find the sourcemap Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
This commit is contained in:
parent
d84f64d2e7
commit
1fefb8e92a
3 changed files with 283 additions and 361 deletions
96
tests/js/tsourcemap.nim
Normal file
96
tests/js/tsourcemap.nim
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
discard """
|
||||
action: "run"
|
||||
target: "js"
|
||||
cmd: "nim js -r -d:nodejs $options --sourceMap:on $file"
|
||||
"""
|
||||
import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings]
|
||||
|
||||
# Implements a very basic sourcemap parser and then runs it on itself.
|
||||
# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052)
|
||||
|
||||
type
|
||||
SourceMap = object
|
||||
version: int
|
||||
sources: seq[string]
|
||||
names: seq[string]
|
||||
mappings: string
|
||||
file: string
|
||||
|
||||
Line = object
|
||||
line, column: int
|
||||
file: string
|
||||
|
||||
const
|
||||
flag = 1 shl 5
|
||||
signBit = 0b1
|
||||
fourBits = 0b1111
|
||||
fiveBits = 0b11111
|
||||
mask = (1 shl 5) - 1
|
||||
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1)
|
||||
for i, b in alphabet.pairs:
|
||||
b64Table[b.ord] = i
|
||||
|
||||
# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim
|
||||
proc importFs*() {.importjs: "var fs = require(\"fs\");".}
|
||||
proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".}
|
||||
importFS()
|
||||
# Read in needed files
|
||||
let
|
||||
jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path)
|
||||
mapFileName = jsFileName & ".map"
|
||||
|
||||
data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap)
|
||||
jsFile = $readFileSync(jsFileName.cstring)
|
||||
|
||||
proc decodeVLQ(inp: string): seq[int] =
|
||||
var
|
||||
shift, value: int
|
||||
for v in inp.mapIt(b64Table[it.ord]):
|
||||
value += (v and mask) shl shift
|
||||
if (v and flag) > 0:
|
||||
shift += 5
|
||||
continue
|
||||
result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1)
|
||||
shift = 0
|
||||
value = 0
|
||||
|
||||
|
||||
# Keep track of state
|
||||
var
|
||||
line = 0
|
||||
source = 0
|
||||
name = 0
|
||||
column = 0
|
||||
jsLine = 1
|
||||
lines: seq[Line]
|
||||
|
||||
for gline in data.mappings.split(';'):
|
||||
jsLine += 1
|
||||
var jsColumn = 0
|
||||
for item in gline.strip().split(','):
|
||||
let value = item.decodeVLQ()
|
||||
doAssert value.len in [0, 1, 4, 5]
|
||||
if value.len == 0:
|
||||
continue
|
||||
jsColumn += value[0]
|
||||
if value.len >= 4:
|
||||
source += value[1]
|
||||
line += value[2]
|
||||
column += value[3]
|
||||
lines &= Line(line: line, column: column, file: data.sources[source])
|
||||
|
||||
let jsLines = jsFile.splitLines().len
|
||||
# There needs to be a mapping for every line in the JS
|
||||
# If there isn't then the JS lines wont match up with Nim lines.
|
||||
# Except we don't care about the final line since that doesn't need to line up
|
||||
doAssert data.mappings.count(';') == jsLines - 1
|
||||
|
||||
# Check we can find this file somewhere in the source map
|
||||
var foundSelf = false
|
||||
for line in lines:
|
||||
if "tsourcemap.nim" in line.file:
|
||||
foundSelf = true
|
||||
doAssert line.line in 0..<jsLines, "Lines is out of bounds for file"
|
||||
doAssert foundSelf, "Couldn't find tsourcemap.nim in source map"
|
||||
Loading…
Add table
Add a link
Reference in a new issue