解码(javascript)源地图

时间:2015-03-25 17:56:57

标签: javascript source-maps

我一直对以下找到的here

图片感到困惑

Decoding the source map

以下描述它应该如何工作:

  

上面的图AAgBC一旦进一步处理将返回0,0,32,16,1 - 32是连续位,有助于构建以下16的值.B在Base64中纯粹解码为1.所以重要的值是使用的是0,0,16,1。然后让我们知道第1行(由冒号保持行数)生成的文件的第0列映射到文件0(文件0的数组是foo.js),第1栏第16行。

我含糊地理解为什么B被转换为16,但是什么是C?以及如何将其转换为1

1 个答案:

答案 0 :(得分:2)

该页面上的解释非常混乱。忘记提及的关键是,base64和VLQ系统基于6位字母,而不是通常的8位字母。例如,base64数据与JavaScript自身的atob函数之类的“常规” base64解码器不兼容(atob("AAgBC")会产生错误)。我认为this page提供了更好的解释。

假设我们有一个函数decodeLine()来解码一行"IACH,mBAA0B,CAAS,EAAE,SAAgB"的数字。这仅是成功的一半,因为4个数组(或5个数组)中的每个数组都相对于先前的4个数组。

在此示例中,第一个base64字符串“ IACH”表示数组[4,0,1,-3],但是此信息本身无用,因为它相对于先前的4数组(第一个数字除外,即在每一行的开头重置为0)。因此,如果先前的4数组的总和为[11,1,10,3],我们可以计算出“ IACH”的实际含义为[4, 1+0, 10+1,3+-3] = [4,1,11,0]-这意味着“输出列4对应于源文件1,源第11行,源列0”。同样,“ mBAA0B”解码为[19,0,0,26],然后将其添加到[4,1,11,0]以得到[23,1,11,26],这意味着“输出列23对应于源文件1,源代码行11,源代码列26”。

因此,我在这里编写了用于解码整个"mappings"字符串的代码。它由两部分组成,decodeLine解码一行,scanMappings解码所有行,并为每个解码的6个值集(行,列,源文件,源行,源列)调用一个函数,以及可选的名称索引):

function decodeLine(line) { 
  function digit(c) { return atob("AAA"+c).charCodeAt(2); }
  if (line==="") return [];
  return line.split(",").map(token => {
    var output = [], num;
    for (var i = 0; i < token.length;) {
      var v = 0, shift = 0;
      do {
        var d = digit(token[i++]);  // d = next 6-bit value decoded from base64
        v |= (d & 31) << shift;     // put lowest 5 bits of d into v
      } while (shift += 5, d & 32); // repeat if high bit of d is set
      output.push(v & 1 ? -(v >> 1) : v >> 1); // low bit is sign
    }
    return output;
  });
}
function scanMappings(data, callback) {
  var lines = data.split(";"), output = [];
  var sum = [0,0,0,0,0];
  for (var line = 0; line < lines.length; line++) {
    sum[0] = 0;
    decodeLine(lines[line]).forEach(p => {
      for (var i = 0; i < p.length; i++) sum[i] += p[i];
      callback(line, ...sum);
    })
  }
}

// Example taken from one of my TypeScript files
console.log(JSON.stringify(decodeLine("IACH,mBAA0B,CAAS,EAAE,SAAgB")));
scanMappings(
 ";;;;;;;;;;;ICAA;;;;;;;;;;OAUG;IACH,mBAA0B,CAAS,EAAE,SAAgB;QACnD,uEAAuE",
  (line,col,srcFile,srcLine,srcCol) => 
    console.log(`(${line},${col}) is from src file ${srcFile} at (${srcLine},${srcCol})`));

行和列从零开始。规范为here