Hatena::ブログ(Diary)

Islands in the byte stream

2012-04-08

source map generatorの使い方

source map rev.3の実装であるsource-mapを調べてみた。

このモジュールの提供するsource map generatorとしては、プリミティブなSourceMapGeneratorとより抽象化したSourceNodeが提供されている。

SourceMapGeneratorは、オリジナルと生成コードの対応関係を一つ一つ自分で追加してゆき、最終的にsource mapを生成する。

SourceNodeはコンパイラがJSを生成する際の中間表現として使うことを想定されており、オリジナルと生成コードの対応の計算をある程度自動的に行なってくれるようだ。

とりあえずSourceMapGeneratorを触ってみる。インターフェイスは極めて単純で、コンストラクタとaddMapping()とtoString()しかない。

#!/usr/bin/env NODE_PATH=lib node
"use strict";

var sourceMap = require('source-map');
var Generator = sourceMap.SourceMapGenerator;
var Consumer  = sourceMap.SourceMapConsumer;

// generate

var gen = new Generator({
    file: 'generated.js',
    sourceRoot: '/path/to/root'
});

gen.addMapping({
    source: 'original.js',
    original:  { line: 1, column: 0 },
    generated: { line: 2, column: 2 },
    name: 'bar' // optional symbol name
});

var map_json = gen.toString();
console.log("// mapping");
console.log(JSON.parse(map_json));

// consume (we don't need it directly)

var consumer = new Consumer(map_json);

var pos = consumer.originalPositionFor({
    line: 2, column: 2
});


console.log("\n" + "// query");
console.log(pos);

結果:

// mapping
{ version: 3,
  file: 'generated.js',
  sources: [ 'original.js' ],
  names: [ 'bar' ],
  mappings: ';EAAAA',
  sourceRoot: '/path/to/root' }

// query
{ source: '/path/to/root/original.js',
  line: 1,
  column: 0,
  name: 'bar' }

source-mapはrequirejsに依存していたりして少し使いづらいが、全体で1000行に満たないコードなので実装は難しくなさそうだ。Dartは一刻もはやくsouce mapに対応すべきだろう。