CoolFace
Apppublic

Pinsave/counterstrike

sourceHugging Faceupdated 3mo agoView on Hugging Face
1likes
README.md766 linesDownload Raw Back to source-map-js
1# Source Map JS2 3[![NPM](https://nodei.co/npm/source-map-js.png?downloads=true&downloadRank=true)](https://www.npmjs.com/package/source-map-js)4 5Difference between original [source-map](https://github.com/mozilla/source-map):6 7> TL,DR: it's fork of original source-map@0.6, but with perfomance optimizations.8 9This journey starts from [source-map@0.7.0](https://github.com/mozilla/source-map/blob/master/CHANGELOG.md#070). Some part of it was rewritten to Rust and WASM and API became async.10 11It's still a major block for many libraries like PostCSS or Sass for example because they need to migrate the whole API to the async way. This is the reason why 0.6.1 has 2x more downloads than 0.7.3 while it's faster several times.12 13![Downloads count](media/downloads.png)14 15More important that WASM version has some optimizations in JS code too. This is why [community asked to create branch for 0.6 version](https://github.com/mozilla/source-map/issues/324) and port these optimizations but, sadly, the answer was «no». A bit later I discovered [the issue](https://github.com/mozilla/source-map/issues/370) created by [Ben Rothman (@benthemonkey)](https://github.com/benthemonkey) with no response at all.16 17[Roman Dvornov (@lahmatiy)](https://github.com/lahmatiy) wrote a [serveral posts](https://t.me/gorshochekvarit/76) (russian, only, sorry) about source-map library in his own Telegram channel. He mentioned the article [«Maybe you don't need Rust and WASM to speed up your JS»](https://mrale.ph/blog/2018/02/03/maybe-you-dont-need-rust-to-speed-up-your-js.html) written by [Vyacheslav Egorov (@mraleph)](https://github.com/mraleph). This article contains optimizations and hacks that lead to almost the same performance compare to WASM implementation.18 19I decided to fork the original source-map and port these optimizations from the article and several others PR from the original source-map.20 21---------22 23This is a library to generate and consume the source map format24[described here][format].25 26[format]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit27 28## Use with Node29 30    $ npm install source-map-js31 32<!-- ## Use on the Web33 34    <script src="https://raw.githubusercontent.com/mozilla/source-map/master/dist/source-map.min.js" defer></script> -->35 36--------------------------------------------------------------------------------37 38<!-- `npm run toc` to regenerate the Table of Contents -->39 40<!-- START doctoc generated TOC please keep comment here to allow auto update -->41<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->42## Table of Contents43 44- [Examples](#examples)45  - [Consuming a source map](#consuming-a-source-map)46  - [Generating a source map](#generating-a-source-map)47    - [With SourceNode (high level API)](#with-sourcenode-high-level-api)48    - [With SourceMapGenerator (low level API)](#with-sourcemapgenerator-low-level-api)49- [API](#api)50  - [SourceMapConsumer](#sourcemapconsumer)51    - [new SourceMapConsumer(rawSourceMap)](#new-sourcemapconsumerrawsourcemap)52    - [SourceMapConsumer.prototype.computeColumnSpans()](#sourcemapconsumerprototypecomputecolumnspans)53    - [SourceMapConsumer.prototype.originalPositionFor(generatedPosition)](#sourcemapconsumerprototypeoriginalpositionforgeneratedposition)54    - [SourceMapConsumer.prototype.generatedPositionFor(originalPosition)](#sourcemapconsumerprototypegeneratedpositionfororiginalposition)55    - [SourceMapConsumer.prototype.allGeneratedPositionsFor(originalPosition)](#sourcemapconsumerprototypeallgeneratedpositionsfororiginalposition)56    - [SourceMapConsumer.prototype.hasContentsOfAllSources()](#sourcemapconsumerprototypehascontentsofallsources)57    - [SourceMapConsumer.prototype.sourceContentFor(source[, returnNullOnMissing])](#sourcemapconsumerprototypesourcecontentforsource-returnnullonmissing)58    - [SourceMapConsumer.prototype.eachMapping(callback, context, order)](#sourcemapconsumerprototypeeachmappingcallback-context-order)59  - [SourceMapGenerator](#sourcemapgenerator)60    - [new SourceMapGenerator([startOfSourceMap])](#new-sourcemapgeneratorstartofsourcemap)61    - [SourceMapGenerator.fromSourceMap(sourceMapConsumer)](#sourcemapgeneratorfromsourcemapsourcemapconsumer)62    - [SourceMapGenerator.prototype.addMapping(mapping)](#sourcemapgeneratorprototypeaddmappingmapping)63    - [SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent)](#sourcemapgeneratorprototypesetsourcecontentsourcefile-sourcecontent)64    - [SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile[, sourceMapPath]])](#sourcemapgeneratorprototypeapplysourcemapsourcemapconsumer-sourcefile-sourcemappath)65    - [SourceMapGenerator.prototype.toString()](#sourcemapgeneratorprototypetostring)66  - [SourceNode](#sourcenode)67    - [new SourceNode([line, column, source[, chunk[, name]]])](#new-sourcenodeline-column-source-chunk-name)68    - [SourceNode.fromStringWithSourceMap(code, sourceMapConsumer[, relativePath])](#sourcenodefromstringwithsourcemapcode-sourcemapconsumer-relativepath)69    - [SourceNode.prototype.add(chunk)](#sourcenodeprototypeaddchunk)70    - [SourceNode.prototype.prepend(chunk)](#sourcenodeprototypeprependchunk)71    - [SourceNode.prototype.setSourceContent(sourceFile, sourceContent)](#sourcenodeprototypesetsourcecontentsourcefile-sourcecontent)72    - [SourceNode.prototype.walk(fn)](#sourcenodeprototypewalkfn)73    - [SourceNode.prototype.walkSourceContents(fn)](#sourcenodeprototypewalksourcecontentsfn)74    - [SourceNode.prototype.join(sep)](#sourcenodeprototypejoinsep)75    - [SourceNode.prototype.replaceRight(pattern, replacement)](#sourcenodeprototypereplacerightpattern-replacement)76    - [SourceNode.prototype.toString()](#sourcenodeprototypetostring)77    - [SourceNode.prototype.toStringWithSourceMap([startOfSourceMap])](#sourcenodeprototypetostringwithsourcemapstartofsourcemap)78 79<!-- END doctoc generated TOC please keep comment here to allow auto update -->80 81## Examples82 83### Consuming a source map84 85```js86var rawSourceMap = {87  version: 3,88  file: 'min.js',89  names: ['bar', 'baz', 'n'],90  sources: ['one.js', 'two.js'],91  sourceRoot: 'http://example.com/www/js/',92  mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'93};94 95var smc = new SourceMapConsumer(rawSourceMap);96 97console.log(smc.sources);98// [ 'http://example.com/www/js/one.js',99//   'http://example.com/www/js/two.js' ]100 101console.log(smc.originalPositionFor({102  line: 2,103  column: 28104}));105// { source: 'http://example.com/www/js/two.js',106//   line: 2,107//   column: 10,108//   name: 'n' }109 110console.log(smc.generatedPositionFor({111  source: 'http://example.com/www/js/two.js',112  line: 2,113  column: 10114}));115// { line: 2, column: 28 }116 117smc.eachMapping(function (m) {118  // ...119});120```121 122### Generating a source map123 124In depth guide:125[**Compiling to JavaScript, and Debugging with Source Maps**](https://hacks.mozilla.org/2013/05/compiling-to-javascript-and-debugging-with-source-maps/)126 127#### With SourceNode (high level API)128 129```js130function compile(ast) {131  switch (ast.type) {132  case 'BinaryExpression':133    return new SourceNode(134      ast.location.line,135      ast.location.column,136      ast.location.source,137      [compile(ast.left), " + ", compile(ast.right)]138    );139  case 'Literal':140    return new SourceNode(141      ast.location.line,142      ast.location.column,143      ast.location.source,144      String(ast.value)145    );146  // ...147  default:148    throw new Error("Bad AST");149  }150}151 152var ast = parse("40 + 2", "add.js");153console.log(compile(ast).toStringWithSourceMap({154  file: 'add.js'155}));156// { code: '40 + 2',157//   map: [object SourceMapGenerator] }158```159 160#### With SourceMapGenerator (low level API)161 162```js163var map = new SourceMapGenerator({164  file: "source-mapped.js"165});166 167map.addMapping({168  generated: {169    line: 10,170    column: 35171  },172  source: "foo.js",173  original: {174    line: 33,175    column: 2176  },177  name: "christopher"178});179 180console.log(map.toString());181// '{"version":3,"file":"source-mapped.js","sources":["foo.js"],"names":["christopher"],"mappings":";;;;;;;;;mCAgCEA"}'182```183 184## API185 186Get a reference to the module:187 188```js189// Node.js190var sourceMap = require('source-map');191 192// Browser builds193var sourceMap = window.sourceMap;194 195// Inside Firefox196const sourceMap = require("devtools/toolkit/sourcemap/source-map.js");197```198 199### SourceMapConsumer200 201A SourceMapConsumer instance represents a parsed source map which we can query202for information about the original file positions by giving it a file position203in the generated source.204 205#### new SourceMapConsumer(rawSourceMap)206 207The only parameter is the raw source map (either as a string which can be208`JSON.parse`'d, or an object). According to the spec, source maps have the209following attributes:210 211* `version`: Which version of the source map spec this map is following.212 213* `sources`: An array of URLs to the original source files.214 215* `names`: An array of identifiers which can be referenced by individual216  mappings.217 218* `sourceRoot`: Optional. The URL root from which all sources are relative.219 220* `sourcesContent`: Optional. An array of contents of the original source files.221 222* `mappings`: A string of base64 VLQs which contain the actual mappings.223 224* `file`: Optional. The generated filename this source map is associated with.225 226```js227var consumer = new sourceMap.SourceMapConsumer(rawSourceMapJsonData);228```229 230#### SourceMapConsumer.prototype.computeColumnSpans()231 232Compute the last column for each generated mapping. The last column is233inclusive.234 235```js236// Before:237consumer.allGeneratedPositionsFor({ line: 2, source: "foo.coffee" })238// [ { line: 2,239//     column: 1 },240//   { line: 2,241//     column: 10 },242//   { line: 2,243//     column: 20 } ]244 245consumer.computeColumnSpans();246 247// After:248consumer.allGeneratedPositionsFor({ line: 2, source: "foo.coffee" })249// [ { line: 2,250//     column: 1,251//     lastColumn: 9 },252//   { line: 2,253//     column: 10,254//     lastColumn: 19 },255//   { line: 2,256//     column: 20,257//     lastColumn: Infinity } ]258 259```260 261#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition)262 263Returns the original source, line, and column information for the generated264source's line and column positions provided. The only argument is an object with265the following properties:266 267* `line`: The line number in the generated source.  Line numbers in268  this library are 1-based (note that the underlying source map269  specification uses 0-based line numbers -- this library handles the270  translation).271 272* `column`: The column number in the generated source.  Column numbers273  in this library are 0-based.274 275* `bias`: Either `SourceMapConsumer.GREATEST_LOWER_BOUND` or276  `SourceMapConsumer.LEAST_UPPER_BOUND`. Specifies whether to return the closest277  element that is smaller than or greater than the one we are searching for,278  respectively, if the exact element cannot be found.  Defaults to279  `SourceMapConsumer.GREATEST_LOWER_BOUND`.280 281and an object is returned with the following properties:282 283* `source`: The original source file, or null if this information is not284  available.285 286* `line`: The line number in the original source, or null if this information is287  not available.  The line number is 1-based.288 289* `column`: The column number in the original source, or null if this290  information is not available.  The column number is 0-based.291 292* `name`: The original identifier, or null if this information is not available.293 294```js295consumer.originalPositionFor({ line: 2, column: 10 })296// { source: 'foo.coffee',297//   line: 2,298//   column: 2,299//   name: null }300 301consumer.originalPositionFor({ line: 99999999999999999, column: 999999999999999 })302// { source: null,303//   line: null,304//   column: null,305//   name: null }306```307 308#### SourceMapConsumer.prototype.generatedPositionFor(originalPosition)309 310Returns the generated line and column information for the original source,311line, and column positions provided. The only argument is an object with312the following properties:313 314* `source`: The filename of the original source.315 316* `line`: The line number in the original source.  The line number is317  1-based.318 319* `column`: The column number in the original source.  The column320  number is 0-based.321 322and an object is returned with the following properties:323 324* `line`: The line number in the generated source, or null.  The line325  number is 1-based.326 327* `column`: The column number in the generated source, or null.  The328  column number is 0-based.329 330```js331consumer.generatedPositionFor({ source: "example.js", line: 2, column: 10 })332// { line: 1,333//   column: 56 }334```335 336#### SourceMapConsumer.prototype.allGeneratedPositionsFor(originalPosition)337 338Returns all generated line and column information for the original source, line,339and column provided. If no column is provided, returns all mappings340corresponding to a either the line we are searching for or the next closest line341that has any mappings. Otherwise, returns all mappings corresponding to the342given line and either the column we are searching for or the next closest column343that has any offsets.344 345The only argument is an object with the following properties:346 347* `source`: The filename of the original source.348 349* `line`: The line number in the original source.  The line number is350  1-based.351 352* `column`: Optional. The column number in the original source.  The353  column number is 0-based.354 355and an array of objects is returned, each with the following properties:356 357* `line`: The line number in the generated source, or null.  The line358  number is 1-based.359 360* `column`: The column number in the generated source, or null.  The361  column number is 0-based.362 363```js364consumer.allGeneratedpositionsfor({ line: 2, source: "foo.coffee" })365// [ { line: 2,366//     column: 1 },367//   { line: 2,368//     column: 10 },369//   { line: 2,370//     column: 20 } ]371```372 373#### SourceMapConsumer.prototype.hasContentsOfAllSources()374 375Return true if we have the embedded source content for every source listed in376the source map, false otherwise.377 378In other words, if this method returns `true`, then379`consumer.sourceContentFor(s)` will succeed for every source `s` in380`consumer.sources`.381 382```js383// ...384if (consumer.hasContentsOfAllSources()) {385  consumerReadyCallback(consumer);386} else {387  fetchSources(consumer, consumerReadyCallback);388}389// ...390```391 392#### SourceMapConsumer.prototype.sourceContentFor(source[, returnNullOnMissing])393 394Returns the original source content for the source provided. The only395argument is the URL of the original source file.396 397If the source content for the given source is not found, then an error is398thrown. Optionally, pass `true` as the second param to have `null` returned399instead.400 401```js402consumer.sources403// [ "my-cool-lib.clj" ]404 405consumer.sourceContentFor("my-cool-lib.clj")406// "..."407 408consumer.sourceContentFor("this is not in the source map");409// Error: "this is not in the source map" is not in the source map410 411consumer.sourceContentFor("this is not in the source map", true);412// null413```414 415#### SourceMapConsumer.prototype.eachMapping(callback, context, order)416 417Iterate over each mapping between an original source/line/column and a418generated line/column in this source map.419 420* `callback`: The function that is called with each mapping. Mappings have the421  form `{ source, generatedLine, generatedColumn, originalLine, originalColumn,422  name }`423 424* `context`: Optional. If specified, this object will be the value of `this`425  every time that `callback` is called.426 427* `order`: Either `SourceMapConsumer.GENERATED_ORDER` or428  `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to iterate over429  the mappings sorted by the generated file's line/column order or the430  original's source/line/column order, respectively. Defaults to431  `SourceMapConsumer.GENERATED_ORDER`.432 433```js434consumer.eachMapping(function (m) { console.log(m); })435// ...436// { source: 'illmatic.js',437//   generatedLine: 1,438//   generatedColumn: 0,439//   originalLine: 1,440//   originalColumn: 0,441//   name: null }442// { source: 'illmatic.js',443//   generatedLine: 2,444//   generatedColumn: 0,445//   originalLine: 2,446//   originalColumn: 0,447//   name: null }448// ...449```450### SourceMapGenerator451 452An instance of the SourceMapGenerator represents a source map which is being453built incrementally.454 455#### new SourceMapGenerator([startOfSourceMap])456 457You may pass an object with the following properties:458 459* `file`: The filename of the generated source that this source map is460  associated with.461 462* `sourceRoot`: A root for all relative URLs in this source map.463 464* `skipValidation`: Optional. When `true`, disables validation of mappings as465  they are added. This can improve performance but should be used with466  discretion, as a last resort. Even then, one should avoid using this flag when467  running tests, if possible.468 469* `ignoreInvalidMapping`: Optional. When `true`, instead of throwing error on470  invalid mapping, it will be ignored.471 472```js473var generator = new sourceMap.SourceMapGenerator({474  file: "my-generated-javascript-file.js",475  sourceRoot: "http://example.com/app/js/"476});477```478 479#### SourceMapGenerator.fromSourceMap(sourceMapConsumer, sourceMapGeneratorOptions)480 481Creates a new `SourceMapGenerator` from an existing `SourceMapConsumer` instance.482 483* `sourceMapConsumer` The SourceMap.484 485* `sourceMapGeneratorOptions` options that will be passed to the SourceMapGenerator constructor which used under the hood.486 487```js488var generator = sourceMap.SourceMapGenerator.fromSourceMap(consumer, {489  ignoreInvalidMapping: true,490});491```492 493#### SourceMapGenerator.prototype.addMapping(mapping)494 495Add a single mapping from original source line and column to the generated496source's line and column for this source map being created. The mapping object497should have the following properties:498 499* `generated`: An object with the generated line and column positions.500 501* `original`: An object with the original line and column positions.502 503* `source`: The original source file (relative to the sourceRoot).504 505* `name`: An optional original token name for this mapping.506 507```js508generator.addMapping({509  source: "module-one.scm",510  original: { line: 128, column: 0 },511  generated: { line: 3, column: 456 }512})513```514 515#### SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent)516 517Set the source content for an original source file.518 519* `sourceFile` the URL of the original source file.520 521* `sourceContent` the content of the source file.522 523```js524generator.setSourceContent("module-one.scm",525                           fs.readFileSync("path/to/module-one.scm"))526```527 528#### SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile[, sourceMapPath]])529 530Applies a SourceMap for a source file to the SourceMap.531Each mapping to the supplied source file is rewritten using the532supplied SourceMap. Note: The resolution for the resulting mappings533is the minimum of this map and the supplied map.534 535* `sourceMapConsumer`: The SourceMap to be applied.536 537* `sourceFile`: Optional. The filename of the source file.538  If omitted, sourceMapConsumer.file will be used, if it exists.539  Otherwise an error will be thrown.540 541* `sourceMapPath`: Optional. The dirname of the path to the SourceMap542  to be applied. If relative, it is relative to the SourceMap.543 544  This parameter is needed when the two SourceMaps aren't in the same545  directory, and the SourceMap to be applied contains relative source546  paths. If so, those relative source paths need to be rewritten547  relative to the SourceMap.548 549  If omitted, it is assumed that both SourceMaps are in the same directory,550  thus not needing any rewriting. (Supplying `'.'` has the same effect.)551 552#### SourceMapGenerator.prototype.toString()553 554Renders the source map being generated to a string.555 556```js557generator.toString()558// '{"version":3,"sources":["module-one.scm"],"names":[],"mappings":"...snip...","file":"my-generated-javascript-file.js","sourceRoot":"http://example.com/app/js/"}'559```560 561### SourceNode562 563SourceNodes provide a way to abstract over interpolating and/or concatenating564snippets of generated JavaScript source code, while maintaining the line and565column information associated between those snippets and the original source566code. This is useful as the final intermediate representation a compiler might567use before outputting the generated JS and source map.568 569#### new SourceNode([line, column, source[, chunk[, name]]])570 571* `line`: The original line number associated with this source node, or null if572  it isn't associated with an original line.  The line number is 1-based.573 574* `column`: The original column number associated with this source node, or null575  if it isn't associated with an original column.  The column number576  is 0-based.577 578* `source`: The original source's filename; null if no filename is provided.579 580* `chunk`: Optional. Is immediately passed to `SourceNode.prototype.add`, see581  below.582 583* `name`: Optional. The original identifier.584 585```js586var node = new SourceNode(1, 2, "a.cpp", [587  new SourceNode(3, 4, "b.cpp", "extern int status;\n"),588  new SourceNode(5, 6, "c.cpp", "std::string* make_string(size_t n);\n"),589  new SourceNode(7, 8, "d.cpp", "int main(int argc, char** argv) {}\n"),590]);591```592 593#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer[, relativePath])594 595Creates a SourceNode from generated code and a SourceMapConsumer.596 597* `code`: The generated code598 599* `sourceMapConsumer` The SourceMap for the generated code600 601* `relativePath` The optional path that relative sources in `sourceMapConsumer`602  should be relative to.603 604```js605var consumer = new SourceMapConsumer(fs.readFileSync("path/to/my-file.js.map", "utf8"));606var node = SourceNode.fromStringWithSourceMap(fs.readFileSync("path/to/my-file.js"),607                                              consumer);608```609 610#### SourceNode.prototype.add(chunk)611 612Add a chunk of generated JS to this source node.613 614* `chunk`: A string snippet of generated JS code, another instance of615   `SourceNode`, or an array where each member is one of those things.616 617```js618node.add(" + ");619node.add(otherNode);620node.add([leftHandOperandNode, " + ", rightHandOperandNode]);621```622 623#### SourceNode.prototype.prepend(chunk)624 625Prepend a chunk of generated JS to this source node.626 627* `chunk`: A string snippet of generated JS code, another instance of628   `SourceNode`, or an array where each member is one of those things.629 630```js631node.prepend("/** Build Id: f783haef86324gf **/\n\n");632```633 634#### SourceNode.prototype.setSourceContent(sourceFile, sourceContent)635 636Set the source content for a source file. This will be added to the637`SourceMap` in the `sourcesContent` field.638 639* `sourceFile`: The filename of the source file640 641* `sourceContent`: The content of the source file642 643```js644node.setSourceContent("module-one.scm",645                      fs.readFileSync("path/to/module-one.scm"))646```647 648#### SourceNode.prototype.walk(fn)649 650Walk over the tree of JS snippets in this node and its children. The walking651function is called once for each snippet of JS and is passed that snippet and652the its original associated source's line/column location.653 654* `fn`: The traversal function.655 656```js657var node = new SourceNode(1, 2, "a.js", [658  new SourceNode(3, 4, "b.js", "uno"),659  "dos",660  [661    "tres",662    new SourceNode(5, 6, "c.js", "quatro")663  ]664]);665 666node.walk(function (code, loc) { console.log("WALK:", code, loc); })667// WALK: uno { source: 'b.js', line: 3, column: 4, name: null }668// WALK: dos { source: 'a.js', line: 1, column: 2, name: null }669// WALK: tres { source: 'a.js', line: 1, column: 2, name: null }670// WALK: quatro { source: 'c.js', line: 5, column: 6, name: null }671```672 673#### SourceNode.prototype.walkSourceContents(fn)674 675Walk over the tree of SourceNodes. The walking function is called for each676source file content and is passed the filename and source content.677 678* `fn`: The traversal function.679 680```js681var a = new SourceNode(1, 2, "a.js", "generated from a");682a.setSourceContent("a.js", "original a");683var b = new SourceNode(1, 2, "b.js", "generated from b");684b.setSourceContent("b.js", "original b");685var c = new SourceNode(1, 2, "c.js", "generated from c");686c.setSourceContent("c.js", "original c");687 688var node = new SourceNode(null, null, null, [a, b, c]);689node.walkSourceContents(function (source, contents) { console.log("WALK:", source, ":", contents); })690// WALK: a.js : original a691// WALK: b.js : original b692// WALK: c.js : original c693```694 695#### SourceNode.prototype.join(sep)696 697Like `Array.prototype.join` except for SourceNodes. Inserts the separator698between each of this source node's children.699 700* `sep`: The separator.701 702```js703var lhs = new SourceNode(1, 2, "a.rs", "my_copy");704var operand = new SourceNode(3, 4, "a.rs", "=");705var rhs = new SourceNode(5, 6, "a.rs", "orig.clone()");706 707var node = new SourceNode(null, null, null, [ lhs, operand, rhs ]);708var joinedNode = node.join(" ");709```710 711#### SourceNode.prototype.replaceRight(pattern, replacement)712 713Call `String.prototype.replace` on the very right-most source snippet. Useful714for trimming white space from the end of a source node, etc.715 716* `pattern`: The pattern to replace.717 718* `replacement`: The thing to replace the pattern with.719 720```js721// Trim trailing white space.722node.replaceRight(/\s*$/, "");723```724 725#### SourceNode.prototype.toString()726 727Return the string representation of this source node. Walks over the tree and728concatenates all the various snippets together to one string.729 730```js731var node = new SourceNode(1, 2, "a.js", [732  new SourceNode(3, 4, "b.js", "uno"),733  "dos",734  [735    "tres",736    new SourceNode(5, 6, "c.js", "quatro")737  ]738]);739 740node.toString()741// 'unodostresquatro'742```743 744#### SourceNode.prototype.toStringWithSourceMap([startOfSourceMap])745 746Returns the string representation of this tree of source nodes, plus a747SourceMapGenerator which contains all the mappings between the generated and748original sources.749 750The arguments are the same as those to `new SourceMapGenerator`.751 752```js753var node = new SourceNode(1, 2, "a.js", [754  new SourceNode(3, 4, "b.js", "uno"),755  "dos",756  [757    "tres",758    new SourceNode(5, 6, "c.js", "quatro")759  ]760]);761 762node.toStringWithSourceMap({ file: "my-output-file.js" })763// { code: 'unodostresquatro',764//   map: [object SourceMapGenerator] }765```766