mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
563 lines
19 KiB
HTML
563 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html>
|
|
<head>
|
|
<title>sourcemap.litcoffee</title>
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
|
|
<link rel="stylesheet" media="all" href="docco.css" />
|
|
</head>
|
|
<body>
|
|
<div id="container">
|
|
<div id="background"></div>
|
|
|
|
<ul id="jump_to">
|
|
<li>
|
|
<a class="large" href="javascript:void(0);">Jump To …</a>
|
|
<a class="small" href="javascript:void(0);">+</a>
|
|
<div id="jump_wrapper">
|
|
<div id="jump_page">
|
|
|
|
|
|
<a class="source" href="browser.html">
|
|
browser.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="cake.html">
|
|
cake.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="coffee-script.html">
|
|
coffee-script.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="command.html">
|
|
command.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="grammar.html">
|
|
grammar.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="helpers.html">
|
|
helpers.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="index.html">
|
|
index.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="lexer.html">
|
|
lexer.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="nodes.html">
|
|
nodes.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="optparse.html">
|
|
optparse.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="repl.html">
|
|
repl.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="rewriter.html">
|
|
rewriter.coffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="scope.html">
|
|
scope.litcoffee
|
|
</a>
|
|
|
|
|
|
<a class="source" href="sourcemap.html">
|
|
sourcemap.litcoffee
|
|
</a>
|
|
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
<ul class="sections">
|
|
|
|
<li id="title">
|
|
<div class="annotation">
|
|
<h1>sourcemap.litcoffee</h1>
|
|
</div>
|
|
</li>
|
|
|
|
|
|
|
|
<li id="section-1">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-1">¶</a>
|
|
</div>
|
|
<p>Source maps allow JavaScript runtimes to match running JavaScript back to
|
|
the original CoffeeScript source code that corresponds to it. In order to
|
|
produce maps, we must keep track of positions (line number, column number)
|
|
for every construct in the syntax tree, and be able to generate a map file
|
|
-- which is a compact, VLQ-encoded representation of the JSON serialization
|
|
of this information -- to write out alongside the generated JavaScript.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>{merge} = require <span class="string">'./helpers'</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-2">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-2">¶</a>
|
|
</div>
|
|
<h2>LineMap</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-3">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-3">¶</a>
|
|
</div>
|
|
<p>Keeps track of information about column positions within a single line of
|
|
output JavaScript code. <strong>SourceMap</strong>s are implemented in terms of <strong>LineMap</strong>s.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">class</span> <span class="title">LineMap</span></span>
|
|
constructor: (<span class="property">@line</span>) ->
|
|
<span class="property">@columns</span> = []
|
|
|
|
add: (column, [sourceLine, sourceColumn], options={}) ->
|
|
<span class="keyword">return</span> <span class="keyword">if</span> <span class="property">@columns</span>[column] <span class="keyword">and</span> options.noReplace
|
|
<span class="property">@columns</span>[column] = {line: <span class="property">@line</span>, column, sourceLine, sourceColumn}
|
|
|
|
sourceLocation: (column) ->
|
|
column-- <span class="keyword">until</span> (mapping = <span class="property">@columns</span>[column]) <span class="keyword">or</span> (column <= <span class="number">0</span>)
|
|
mapping <span class="keyword">and</span> [mapping.sourceLine, mapping.sourceColumn]</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-4">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-4">¶</a>
|
|
</div>
|
|
<h2>SourceMap</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-5">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-5">¶</a>
|
|
</div>
|
|
<p>Maps locations in for a single generated JavaScript file back to locations in
|
|
the original CoffeeScript source file.
|
|
|
|
</p>
|
|
<p>This is intentionally agnostic towards how a source map might be represented on
|
|
disk. Once the compiler is ready to produce a "v3"-style source map, we can walk
|
|
through the arrays of line and column buffer to produce it.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">class</span> <span class="title">SourceMap</span></span>
|
|
constructor: ->
|
|
<span class="property">@lines</span> = []</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-6">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-6">¶</a>
|
|
</div>
|
|
<p>Adds a mapping to this SourceMap. <code>sourceLocation</code> and <code>generatedLocation</code>
|
|
are both <code>[line, column]</code> arrays. If <code>options.noReplace</code> is true, then if there
|
|
is already a mapping for the specified <code>line</code> and <code>column</code>, this will have no
|
|
effect.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> add: (sourceLocation, generatedLocation, options = {}) ->
|
|
[line, column] = generatedLocation
|
|
lineMap = (<span class="property">@lines</span>[line] <span class="keyword">or</span>= <span class="keyword">new</span> LineMap(line))
|
|
lineMap.add column, sourceLocation, options</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-7">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-7">¶</a>
|
|
</div>
|
|
<p>Look up the original position of a given <code>line</code> and <code>column</code> in the generated
|
|
code.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> sourceLocation: ([line, column]) ->
|
|
line-- <span class="keyword">until</span> (lineMap = <span class="property">@lines</span>[line]) <span class="keyword">or</span> (line <= <span class="number">0</span>)
|
|
lineMap <span class="keyword">and</span> lineMap.sourceLocation column</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-8">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-8">¶</a>
|
|
</div>
|
|
<h2>V3 SourceMap Generation</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-9">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-9">¶</a>
|
|
</div>
|
|
<p>Builds up a V3 source map, returning the generated JSON as a string.
|
|
<code>options.sourceRoot</code> may be used to specify the sourceRoot written to the source
|
|
map. Also, <code>options.sourceFiles</code> and <code>options.generatedFile</code> may be passed to
|
|
set "sources" and "file", respectively.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> generate: (options = {}, code = <span class="literal">null</span>) ->
|
|
writingline = <span class="number">0</span>
|
|
lastColumn = <span class="number">0</span>
|
|
lastSourceLine = <span class="number">0</span>
|
|
lastSourceColumn = <span class="number">0</span>
|
|
needComma = <span class="literal">no</span>
|
|
buffer = <span class="string">""</span>
|
|
|
|
<span class="keyword">for</span> lineMap, lineNumber <span class="keyword">in</span> <span class="property">@lines</span> <span class="keyword">when</span> lineMap
|
|
<span class="keyword">for</span> mapping <span class="keyword">in</span> lineMap.columns <span class="keyword">when</span> mapping
|
|
<span class="keyword">while</span> writingline < mapping.line
|
|
lastColumn = <span class="number">0</span>
|
|
needComma = <span class="literal">no</span>
|
|
buffer += <span class="string">";"</span>
|
|
writingline++</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-10">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-10">¶</a>
|
|
</div>
|
|
<p>Write a comma if we've already written a segment on this line.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> needComma
|
|
buffer += <span class="string">","</span>
|
|
needComma = <span class="literal">no</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-11">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-11">¶</a>
|
|
</div>
|
|
<p>Write the next segment. Segments can be 1, 4, or 5 values. If just one, then it
|
|
is a generated column which doesn't match anything in the source code.
|
|
|
|
</p>
|
|
<p>The starting column in the generated source, relative to any previous recorded
|
|
column for the current line:
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> buffer += <span class="property">@encodeVlq</span> mapping.column - lastColumn
|
|
lastColumn = mapping.column</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-12">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-12">¶</a>
|
|
</div>
|
|
<p>The index into the list of sources:
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> buffer += <span class="property">@encodeVlq</span> <span class="number">0</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-13">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-13">¶</a>
|
|
</div>
|
|
<p>The starting line in the original source, relative to the previous source line.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> buffer += <span class="property">@encodeVlq</span> mapping.sourceLine - lastSourceLine
|
|
<span class="keyword">if</span> lastSourceLine <span class="keyword">isnt</span> mapping.sourceLine
|
|
lastSourceLine = mapping.sourceLine
|
|
lastSourceColumn = <span class="number">0</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-14">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-14">¶</a>
|
|
</div>
|
|
<p>The starting column in the original source, relative to the previous column.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> buffer += <span class="property">@encodeVlq</span> mapping.sourceColumn - lastSourceColumn
|
|
lastSourceColumn = mapping.sourceColumn
|
|
needComma = <span class="literal">yes</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-15">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-15">¶</a>
|
|
</div>
|
|
<p>Produce the canonical JSON object format for a "v3" source map.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> v3 =
|
|
version: <span class="number">3</span>
|
|
file: options.generatedFile <span class="keyword">or</span> <span class="string">''</span>
|
|
sourceRoot: options.sourceRoot <span class="keyword">or</span> <span class="string">''</span>
|
|
sources: options.sourceFiles <span class="keyword">or</span> [<span class="string">''</span>]
|
|
names: []
|
|
mappings: buffer
|
|
|
|
v3.sourcesContent = [code] <span class="keyword">if</span> options.inline
|
|
|
|
JSON.stringify v3, <span class="literal">null</span>, <span class="number">2</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-16">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-16">¶</a>
|
|
</div>
|
|
<h2>Base64 VLQ Encoding</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-17">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-17">¶</a>
|
|
</div>
|
|
<p>Note that SourceMap VLQ encoding is "backwards". MIDI-style VLQ encoding puts
|
|
the most-significant-bit (MSB) from the original value into the MSB of the VLQ
|
|
encoded value (see <a href="http://en.wikipedia.org/wiki/File:Uintvar_coding.svg">Wikipedia</a>).
|
|
SourceMap VLQ does things the other way around, with the least significat four
|
|
bits of the original value encoded into the first byte of the VLQ encoded value.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> VLQ_SHIFT = <span class="number">5</span>
|
|
VLQ_CONTINUATION_BIT = <span class="number">1</span> << VLQ_SHIFT <span class="comment"># 0010 0000</span>
|
|
VLQ_VALUE_MASK = VLQ_CONTINUATION_BIT - <span class="number">1</span> <span class="comment"># 0001 1111</span>
|
|
|
|
encodeVlq: (value) ->
|
|
answer = <span class="string">''</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-18">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-18">¶</a>
|
|
</div>
|
|
<p>Least significant bit represents the sign.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> signBit = <span class="keyword">if</span> value < <span class="number">0</span> <span class="keyword">then</span> <span class="number">1</span> <span class="keyword">else</span> <span class="number">0</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-19">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-19">¶</a>
|
|
</div>
|
|
<p>The next bits are the actual value.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> valueToEncode = (Math.abs(value) << <span class="number">1</span>) + signBit</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-20">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-20">¶</a>
|
|
</div>
|
|
<p>Make sure we encode at least one character, even if valueToEncode is 0.
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">while</span> valueToEncode <span class="keyword">or</span> <span class="keyword">not</span> answer
|
|
nextChunk = valueToEncode & VLQ_VALUE_MASK
|
|
valueToEncode = valueToEncode >> VLQ_SHIFT
|
|
nextChunk |= VLQ_CONTINUATION_BIT <span class="keyword">if</span> valueToEncode
|
|
answer += <span class="property">@encodeBase64</span> nextChunk
|
|
|
|
answer</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-21">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap for-h2">
|
|
<a class="pilcrow" href="#section-21">¶</a>
|
|
</div>
|
|
<h2>Regular Base64 Encoding</h2>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-22">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-22">¶</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> BASE64_CHARS = <span class="string">'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'</span>
|
|
|
|
encodeBase64: (value) ->
|
|
BASE64_CHARS[value] <span class="keyword">or</span> <span class="keyword">throw</span> <span class="keyword">new</span> Error <span class="string">"Cannot Base64 encode value: <span class="subst">#{value}</span>"</span></pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-23">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-23">¶</a>
|
|
</div>
|
|
<p>Our API for source maps is just the <code>SourceMap</code> class.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre>module.exports = SourceMap</pre></div></div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|