source-map, 使用和生成源映射

分享于 

28分钟阅读

GitHub

  繁體 雙語
Forked from mozilla/source-map. Parse and consume source maps using a closest match algorithm where exact mappings between generated and original are not found.
  • 源代码名称:source-map
  • 源代码网址:http://www.github.com/mozilla/source-map
  • source-map源代码文档
  • source-map源代码下载
  • Git URL:
    git://www.github.com/mozilla/source-map.git
    Git Clone代码到本地:
    git clone http://www.github.com/mozilla/source-map
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/mozilla/source-map
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    源映射

    Build Status

    NPM

    这是一个生成和使用源地图格式的库( 这里是描述的)。

    与 node 一起使用

    
    $ npm install source-map
    
    
    
    

    在网络上使用

    
    <script src="https://unpkg.com/source-map@0.7.0/dist/source-map.js"></script>
    
    
    <script>
    
    
     sourceMap.SourceMapConsumer.initialize({
    
    
    "lib/mappings.wasm":"https://unpkg.com/source-map@0.7.0/lib/mappings.wasm"
    
    
     });
    
    
    </script>
    
    
    
    

    目录

    示例

    使用源映射

    constrawSourceMap= {
     version:3,
     file:'min.js',
     names: ['bar', 'baz', 'n'],
     sources: ['one.js', 'two.js'],
     sourceRoot:'http://example.com/www/js/',
     mappings:'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'};constwhatever=awaitSourceMapConsumer.with(rawSourceMap, null, consumer=> {
     console.log(consumer.sources);
     // [ 'http://example.com/www/js/one.js',// 'http://example.com/www/js/two.js' ]console.log(consumer.originalPositionFor({
     line:2,
     column:28 }));
     // { source: 'http://example.com/www/js/two.js',// line: 2,// column: 10,// name: 'n' }console.log(consumer.generatedPositionFor({
     source:'http://example.com/www/js/two.js',
     line:2,
     column:10 }));
     // { line: 2, column: 28 }consumer.eachMapping(function (m) {
     //.. . });
     returncomputeWhatever();
    });

    生成源映射

    深度指南:编译到 JavaScript,并用源图调试。

    带有 SourceNode ( 高级 API )的
    functioncompile(ast) {
     switch (ast.type) {
     case'BinaryExpression':
     returnnewSourceNode(
     ast.location.line,
     ast.location.column,
     ast.location.source,
     [compile(ast.left), " + ", compile(ast.right)]
     );
     case'Literal':
     returnnewSourceNode(
     ast.location.line,
     ast.location.column,
     ast.location.source,
     String(ast.value)
     );
     //.. .default:
     thrownewError("Bad AST");
     }
    }var ast =parse("40 + 2", "add.js");console.log(compile(ast).toStringWithSourceMap({
     file:'add.js'}));// { code: '40 + 2',// map: [object SourceMapGenerator] }
    带有 SourceMapGenerator ( 低级 API )的
    var map =newSourceMapGenerator({
     file:"source-mapped.js"});map.addMapping({
     generated: {
     line:10,
     column:35 },
     source:"foo.js",
     original: {
     line:33,
     column:2 },
     name:"christopher"});console.log(map.toString());// '{"version":3,"file":"source-mapped.js","sources":["foo.js"],"names":["christopher"],"mappings":";;;;;;;;;mCAgCEA"}'

    API

    获取对模块的引用:

    // Node.jsvar sourceMap =require('source-map');// Browser buildsvar sourceMap =window.sourceMap;// Inside FirefoxconstsourceMap=require("devtools/toolkit/sourcemap/source-map.js");

    SourceMapConsumer

    SourceMapConsumer 实例表示经过解析的源映射,我们可以通过在生成的源文件中提供文件位置来查询关于原始文件位置的信息。

    SourceMapConsumer.initialize(options )

    当在 node.js 之外使用 SourceMapConsumer 时,例如在网络上,它需要知道加载 lib/mappings.wasm的URL。 你必须在构造任何 SourceMapConsumer 之前通过调用 initialize 通知它。

    options对象具有以下属性:

    • "lib/mappings.wasm": 包含 lib/mappings.wasm 文件的URL的String
    sourceMap.SourceMapConsumer.initialize({
     "lib/mappings.wasm":"https://example.com/source-map/lib/mappings.wasm"});
    new SourceMapConsumer(rawSourceMap )

    唯一的参数是原始源映射( 可以是 JSON.parse的字符串,也可以是对象)。 根据规范,源映射具有以下属性:

    • version: 这里映射的源映射规范的版本。

    • sources: 指向原始源文件的url的array。

    • names: 可以由单个映射引用的标识符的array。

    • sourceRoot: 可选的URL root,所有源都是相对的。

    • sourcesContent: 可选的原始源文件的一个 array。

    • mappings: 包含实际映射的base64 VLQs字符串。

    • file: 可选的生成的文件名与这里源映射相关联。

    构建souce地图使用者的承诺。

    当不再使用 SourceMapConsumer 时,必须调用它的destroy 方法。

    constconsumer=awaitnewsourceMap.SourceMapConsumer(rawSourceMapJsonData);doStuffWith(consumer);consumer.destroy();

    或者,可以使用 SourceMapConsumer.with 避免忘记调用 destroy

    SourceMapConsumer.with

    rawSourceMapsourceMapUrl 构造一个新的SourceMapConsumer ( 参见 SourceMapConsumer 构造器了解详细信息。 然后,调用 async function f(SourceMapConsumer) -> T 使用新构造的消费者,等待 f 完成,对消费者调用 destroy,并返回值的f 返回。

    f 完成后,你不能使用使用者 !

    通过使用 with,你不必记住在消费者上手动调用 destroy,因为它会在 f 完成后自动调用。

    constxSquared=awaitSourceMapConsumer.with(
     myRawSourceMap,
     null,
     asyncfunction (consumer) {
     // Use `consumer` inside here and don't worry about remembering// to call `destroy`.constx=awaitwhatever(consumer);
     return x * x;
     }
    );// You may not use that `consumer` anymore out here; it has// been destroyed. But you can use `xSquared`.console.log(xSquared);
    SourceMapConsumer.prototype.destroy( )

    释放与手动管理的使用者wasm数据关联的源映射。

    consumer.destroy();

    或者,可以使用 SourceMapConsumer.with 避免忘记调用 destroy

    SourceMapConsumer.prototype.computeColumnSpans()

    计算每个生成映射的最后一列。 最后一列是包含的。

    // Before:consumer.allGeneratedPositionsFor({ line:2, source:"foo.coffee" })// [ { line: 2,// column: 1 },// { line: 2,// column: 10 },// { line: 2,// column: 20 } ]consumer.computeColumnSpans();// After:consumer.allGeneratedPositionsFor({ line:2, source:"foo.coffee" })// [ { line: 2,// column: 1,// lastColumn: 9 },// { line: 2,// column: 10,// lastColumn: 19 },// { line: 2,// column: 20,// lastColumn: Infinity } ]
    SourceMapConsumer.prototype.originalPositionFor(generatedPosition )

    返回所提供的源和列位置所生成行的原始源。行和列信息。 唯一的参数是具有以下属性的对象:

    • line: 生成的源代码中的行号。 这个库中的行号是 1-based ( 注意,底层源映射规范使用 0-based 行号--这个库处理翻译)。

    • column: 生成的源中的列号。 这里库中的列数为 0 -based。

    • bias: 要么 SourceMapConsumer.GREATEST_LOWER_BOUND 或者 SourceMapConsumer.LEAST_UPPER_BOUND 指定如果找不到确切的元素,是否返回小于或者大于我们搜索的最近元素。 默认为 SourceMapConsumer.GREATEST_LOWER_BOUND

    将返回具有以下属性的对象:

    • source: 原始源文件,如果这里信息不可用,则为 null。

    • line: 原始源中的行号,如果这里信息不可用,则为空。 行号为 1 -based。

    • column: 原始源中的列号,如果这里信息不可用,则为空。 列号为 0 -based。

    • name: 原始标识符,如果这里信息不可用,则为 null。

    consumer.originalPositionFor({ line:2, column:10 })// { source: 'foo.coffee',// line: 2,// column: 2,// name: null }consumer.originalPositionFor({ line:99999999999999999, column:999999999999999 })// { source: null,// line: null,// column: null,// name: null }
    SourceMapConsumer.prototype.generatedPositionFor(originalPosition )

    返回所提供的原始源。行和列位置所生成的行和列信息。 唯一的参数是具有以下属性的对象:

    • source: 原始源的文件名。

    • line: 原始源中的行号。 行号为 1 -based。

    • column: 原始源中的列号。 列号为 0 -based。

    将返回具有以下属性的对象:

    • line: 生成的源中的行号,或者 null。 行号为 1 -based。

    • column: 生成的源中的列号,或者 null。 列号为 0 -based。

    consumer.generatedPositionFor({ source:"example.js", line:2, column:10 })// { line: 1,// column: 56 }
    SourceMapConsumer.prototype.allGeneratedPositionsFor(originalPosition )

    返回所提供的原始源。行和列的所有生成行和列信息。 如果未提供任何列,则返回所有与我们搜索的行或者下一行有任何映射的映射。 否则,返回对应于给定行和我们搜索的列的所有映射,或者包含任何偏移的下一个最近的列。

    唯一的参数是具有以下属性的对象:

    • source: 原始源的文件名。

    • line: 原始源中的行号。 行号为 1 -based。

    • column: 可选。原始源中的列号。 列号为 0 -based。

    返回对象的array,每个对象具有以下属性:

    • line: 生成的源中的行号,或者 null。 行号为 1 -based。

    • column: 生成的源中的列号,或者 null。 列号为 0 -based。

    consumer.allGeneratedpositionsfor({ line:2, source:"foo.coffee" })// [ { line: 2,// column: 1 },// { line: 2,// column: 10 },// { line: 2,// column: 20 } ]
    SourceMapConsumer.prototype.hasContentsOfAllSources( )

    如果源映射中列出的每个源都有嵌入源内容,则返回 true,否则返回 false。

    换句话说,如果这里方法返回 true,那么 consumer.sourceContentFor(s) 将在 consumer.sources 中的每个源 s 中成功。

    //.. .if (consumer.hasContentsOfAllSources()) {
     consumerReadyCallback(consumer);
    } else {
     fetchSources(consumer, consumerReadyCallback);
    }//.. .
    SourceMapConsumer.prototype.sourceContentFor(source [, returnNullOnMissing] )

    返回提供源的原始源内容。 唯一的参数是原始源文件的URL。

    如果找不到给定源的源内容,则会引发错误。 可以选择将 true 作为第二个参数传递,而返回 null

    consumer.sources// ["my-cool-lib.clj" ]consumer.sourceContentFor("my-cool-lib.clj")//"..."consumer.sourceContentFor("this is not in the source map");// Error:"this is not in the source map" is not in the source mapconsumer.sourceContentFor("this is not in the source map", true);// null
    SourceMapConsumer.prototype.eachMapping(callback, context, order )

    迭代原始 source/line/column 与源映射中生成的行/列之间的每个映射。

    • callback: 每个映射调用的函数。 映射具有窗体 { source, generatedLine, generatedColumn, originalLine, originalColumn, name }

    • context: 可选。如果指定,每次调用 callback 时,这里对象将是 this的值。

    • order: SourceMapConsumer.GENERATED_ORDER 或者 SourceMapConsumer.ORIGINAL_ORDER。 指定是否要循环访问按文件顺序生成的行/列或者原始顺序的source/line/column 分类的映射。 默认为 SourceMapConsumer.GENERATED_ORDER

    consumer.eachMapping(function (m) { console.log(m); })//.. .// { source: 'illmatic.js',// generatedLine: 1,// generatedColumn: 0,// originalLine: 1,// originalColumn: 0,// name: null }// { source: 'illmatic.js',// generatedLine: 2,// generatedColumn: 0,// originalLine: 2,// originalColumn: 0,// name: null }//.. .

    SourceMapGenerator

    一个SourceMapGenerator实例表示增量构建的源映射。

    new SourceMapGenerator( [startOfSourceMap] )

    可以通过以下属性传递对象:

    • file: 源映射与之关联的生成源的文件名。

    • sourceRoot: 这里源映射中所有 relative url的root。

    • skipValidation: 可选。当 true 在添加时禁用映射的验证。 这可以提高性能,但应该谨慎使用,作为最后的手段。 即使在运行测试时,也应该避免使用这里标志。

    var generator =newsourceMap.SourceMapGenerator({
     file:"my-generated-javascript-file.js",
     sourceRoot:"http://example.com/app/js/"});
    SourceMapGenerator.fromSourceMap(sourceMapConsumer )

    从现有的SourceMapConsumer 实例创建新的SourceMapGenerator

    • SourceMapConsumer SourceMap。
    var generator =sourceMap.SourceMapGenerator.fromSourceMap(consumer);
    SourceMapGenerator.prototype.addMapping(mapping )

    从原始源行和列添加单个映射到创建的源映射的源和列的生成行。 映射对象应该具有以下属性:

    • generated: 具有生成的行和列位置的对象。

    • original: 具有原始行和列位置的对象。

    • source: 原始源文件( 相对于 sourceRoot )。

    • name: 这里映射的可选原始令牌名称。

    generator.addMapping({
     source:"module-one.scm",
     original: { line:128, column:0 },
     generated: { line:3, column:456 }
    })
    SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent )

    设置原始源文件的源内容。

    • sourceFile 原始源文件的URL。

    • sourceContent 源文件的内容。

    generator.setSourceContent("module-one.scm",
     fs.readFileSync("path/to/module-one.scm"))
    SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer [, sourceFile[, sourceMapPath] ] )

    将源文件的SourceMap应用于 SourceMap。 使用提供的SourceMap重写所提供的源文件的每个映射。 注:结果映射的分辨率是这里映射的最小值和所提供的映射。

    • SourceMapConsumer: 要应用的SourceMap。

    • sourceFile: 可选的源文件的文件名。 如果省略,sourceMapConsumer.file 将被使用,如果存在的话。 否则将引发错误。

    • sourceMapPath: 可选的要应用到的SourceMap路径的子目录。 如果是 relative,它是 relative 到 SourceMap。

      如果两个SourceMaps不在同一目录中,并且要应用的SourceMap包含 relative 源路径,则需要此参数。 如果是,那么那些 relative 源路径需要重写 relative 到 SourceMap。

      如果省略,假设SourceMaps都位于同一目录中,因此不需要重写。 ( 提供 '.' 具有相同的效果。)

    SourceMapGenerator.prototype.toString( )

    将生成的源映射呈现给字符串。

    generator.toString()// '{"version":3,"sources":["module-one.scm"],"names":[],"mappings":"...snip...","file":"my-generated-javascript-file.js","sourceRoot":"http://example.com/app/js/"}'

    SourceNode

    SourceNodes提供了抽象插入和/或者串联生成的JavaScript源代码段的方法,同时维护这些代码段与原始源代码。 这在输出生成的JS和源映射之前,final 中间表示可以使用的中间表示。

    new SourceNode( [line, column, source[, chunk[, name] ]] )
    • line: 与这里源 node 关联的原始行号,如果它没有与原始行关联,则为 null。 行号为 1 -based。

    • column: 与这里源 node 关联的原始列号,如果它没有与原始列关联,则为 null。 列号为 0 -based。

    • source: 源的原始文件名;如果未提供文件名,则为 null。

    • chunk: 可选的,立即传递到 SourceNode.prototype.add,请参阅下面。

    • name: 可选的原始标识符。

    var node =newSourceNode(1, 2, "a.cpp", [
     newSourceNode(3, 4, "b.cpp", "extern int status;n"),
     newSourceNode(5, 6, "c.cpp", "std::string* make_string(size_t n);n"),
     newSourceNode(7, 8, "d.cpp", "int main(int argc, char** argv) {}n"),
    ]);
    SourceNode.fromStringWithSourceMap(code, sourceMapConsumer [, relativePath] )

    从生成的代码和SourceMapConsumer创建一个 SourceNode。

    • code: 生成的代码

    • SourceMapConsumer 生成代码的SourceMap

    • relativePath: SourceMapConsumer 中 relative 源应为 relative的可选路径。

    constconsumer=awaitnewSourceMapConsumer(fs.readFileSync("path/to/my-file.js.map", "utf8"));
    onst node =SourceNode.fromStringWithSourceMap(fs.readFileSync("path/to/my-file.js"),
     consumer);
    SourceNode.prototype.add(chunk )

    将生成的JS块添加到这个源 node。

    • chunk: 生成的JS代码的字符串 Fragment,SourceNode的另一个实例或者 array,每个成员都是其中之一。
    node.add(" + ");node.add(otherNode);node.add([leftHandOperandNode, " + ", rightHandOperandNode]);
    SourceNode.prototype.prepend(chunk )

    将生成的JS块添加到这个源 node。

    • chunk: 生成的JS代码的字符串 Fragment,SourceNode的另一个实例或者 array,每个成员都是其中之一。
    node.prepend("/** Build Id: f783haef86324gf **/nn");
    SourceNode.prototype.setSourceContent(sourceFile, sourceContent )

    设置源文件的源内容。 这将被添加到 sourcesContent 字段中的SourceMap

    • sourceFile: 源文件的文件名

    • sourceContent: 源文件的内容

    node.setSourceContent("module-one.scm",
     fs.readFileSync("path/to/module-one.scm"))
    SourceNode.prototype.walk(fn )

    在这个 node 及其子元素中遍历 JS Fragment的树。 of函数对JS的每个代码片段调用一次,并传递该代码段及它的源位置的原始相关行/列。

    • fn: 遍历函数。
    var node =newSourceNode(1, 2, "a.js", [
     newSourceNode(3, 4, "b.js", "uno"),
     "dos",
     [
     "tres",
     newSourceNode(5, 6, "c.js", "quatro")
     ]
    ]);node.walk(function (code, loc) { console.log("WALK:", code, loc); })// WALK: uno { source: 'b.js', line: 3, column: 4, name: null }// WALK: dos { source: 'a.js', line: 1, column: 2, name: null }// WALK: tres { source: 'a.js', line: 1, column: 2, name: null }// WALK: quatro { source: 'c.js', line: 5, column: 6, name: null }
    SourceNode.prototype.walkSourceContents(fn )

    遍历SourceNodes树。 对于每个源文件内容,都会调用walk函数,并传递文件名和源内容。

    • fn: 遍历函数。
    var a =newSourceNode(1, 2, "a.js", "generated from a");a.setSourceContent("a.js", "original a");var b =newSourceNode(1, 2, "b.js", "generated from b");b.setSourceContent("b.js", "original b");var c =newSourceNode(1, 2, "c.js", "generated from c");c.setSourceContent("c.js", "original c");var node =newSourceNode(null, null, null, [a, b, c]);node.walkSourceContents(function (source, contents) { console.log("WALK:", source, ":", contents); })// WALK: a.js : original a// WALK: b.js : original b// WALK: c.js : original c
    SourceNode.prototype.join(sep )

    Array.prototype.join,除了 SourceNodes。 在 node的每个源子级之间插入分隔符。

    • sep: 分隔符。
    var lhs =newSourceNode(1, 2, "a.rs", "my_copy");var operand =newSourceNode(3, 4, "a.rs", "=");var rhs =newSourceNode(5, 6, "a.rs", "orig.clone()");var node =newSourceNode(null, null, null, [ lhs, operand, rhs ]);var joinedNode =node.join("");
    SourceNode.prototype.replaceRight(pattern, replacement )

    在最右边的源代码Fragment中调用 String.prototype.replace。 用于从源 node的末尾修剪空白,等等。

    • pattern: 要替换的Pattern。

    • replacement: 要替换 Pattern的内容。

    // Trim trailing white space.node.replaceRight(/s*$/, "");
    SourceNode.prototype.toString( )

    返回这里源 node的字符串表示形式。 遍历树并将所有的Fragment连接到一个字符串。

    var node =newSourceNode(1, 2, "a.js", [
     newSourceNode(3, 4, "b.js", "uno"),
     "dos",
     [
     "tres",
     newSourceNode(5, 6, "c.js", "quatro")
     ]
    ]);node.toString()// 'unodostresquatro'
    SourceNode.prototype.toStringWithSourceMap( [startOfSourceMap] )

    返回源节点树的字符串表示,以及包含所生成源和原始源之间的所有映射的SourceMapGenerator。

    参数与 new SourceMapGenerator 中的参数相同。

    var node =newSourceNode(1, 2, "a.js", [
     newSourceNode(3, 4, "b.js", "uno"),
     "dos",
     [
     "tres",
     newSourceNode(5, 6, "c.js", "quatro")
     ]
    ]);node.toStringWithSourceMap({ file:"my-output-file.js" })// { code: 'unodostresquatro',// map: [object SourceMapGenerator] }

    相关文章