UNPKG

@masala/parser

Version:
437 lines (420 loc) 31.2 kB
<!doctype html> <html class="default no-js"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>@masala/parser</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="assets/css/main.css"> </head> <body> <header> <div class="tsd-page-toolbar"> <div class="container"> <div class="table-wrap"> <div class="table-cell" id="tsd-search" data-index="assets/js/search.js" data-base="."> <div class="field"> <label for="tsd-search-field" class="tsd-widget search no-caption">Search</label> <input id="tsd-search-field" type="text" /> </div> <ul class="results"> <li class="state loading">Preparing search index...</li> <li class="state failure">The search index is not available</li> </ul> <a href="index.html" class="title">@masala/parser</a> </div> <div class="table-cell" id="tsd-widgets"> <div id="tsd-filter"> <a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a> <div class="tsd-filter-group"> <div class="tsd-select" id="tsd-filter-visibility"> <span class="tsd-select-label">All</span> <ul class="tsd-select-list"> <li data-value="public">Public</li> <li data-value="protected">Public/Protected</li> <li data-value="private" class="selected">All</li> </ul> </div> <input type="checkbox" id="tsd-filter-inherited" checked /> <label class="tsd-widget" for="tsd-filter-inherited">Inherited</label> <input type="checkbox" id="tsd-filter-only-exported" /> <label class="tsd-widget" for="tsd-filter-only-exported">Only exported</label> </div> </div> <a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a> </div> </div> </div> </div> <div class="tsd-page-title"> <div class="container"> <ul class="tsd-breadcrumb"> <li> <a href="globals.html">Globals</a> </li> </ul> <h1> @masala/parser</h1> </div> </div> </header> <div class="container container-main"> <div class="row"> <div class="col-8 col-content"> <div class="tsd-panel tsd-typography"> <h1 id="masala-parser-javascript-parser-combinators">Masala Parser: Javascript Parser Combinators</h1> <p><a href="https://badge.fury.io/js/%40masala%2Fparser"><img src="https://badge.fury.io/js/%40masala%2Fparser.svg" alt="npm version"></a> <a href="https://travis-ci.org/d-plaindoux/masala-parser"><img src="https://travis-ci.org/d-plaindoux/masala-parser.svg" alt="Build Status"></a> <a href="https://coveralls.io/r/d-plaindoux/masala-parser?branch=master"><img src="https://coveralls.io/repos/d-plaindoux/masala-parser/badge.png?branch=master" alt="Coverage Status"></a> <a href="http://github.com/badges/stability-badges"><img src="http://badges.github.io/stability-badges/dist/stable.svg" alt="stable"></a></p> <p>Masala Parser is inspired by the paper titled: <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/parsec-paper-letter.pdf">Direct Style Monadic Parser Combinators For The Real World</a>.</p> <p>Masala Parser is a Javascript implementation of the Haskell <strong>Parsec</strong>. It is plain Javascript that works in the browser, is tested with more than 450 unit tests, covering 100% of code lines.</p> <h3 id="use-cases">Use cases</h3> <ul> <li>It can create a <strong>full parser from scratch</strong></li> <li>It can extract data from a big text and <strong>replace complex regexp</strong></li> <li>It works in any <strong>browser</strong></li> <li>There is a good <strong>typescript</strong> type declaration</li> <li>It can validate complete structure with <strong>variations</strong></li> <li>It&#39;s a great starting point for parser education. It&#39;s <strong>way simpler than Lex &amp; Yacc</strong>.</li> <li>It&#39;s designed to be written in other languages (Python, Java, Rust) with the same interface</li> </ul> <p>Masala Parser keywords are <strong>simplicity</strong>, <strong>variations</strong> and <strong>maintainability</strong>. You won&#39;t need theoretical bases on languages for extraction or validation use cases.</p> <p>Masala Parser has relatively good performances, however Javascript is obviously not the fastest machine.</p> <h1 id="usage">Usage</h1> <p>With Node Js or modern build </p> <pre><code> <span class="hljs-built_in">npm</span> install -S @masala/parser</code></pre><p>Or in the browser </p> <ul> <li><a href="https://github.com/d-plaindoux/masala-parser/releases">download Release</a></li> <li><code>&lt;script src=&quot;masala-parser.min.js&quot;/&gt;</code></li> </ul> <p>Check the <a href="./changelog.md">Change Log</a> if you can from a previous version.</p> <h1 id="reference">Reference</h1> <p>You will find an <a href="documentation/typedoc/modules/_masala_parser_d_.html">Masala Parser online reference</a>, generated from typescript interface.</p> <h1 id="quick-examples">Quick Examples</h1> <h2 id="hello-world">Hello World</h2> <pre><code class="language-js"><span class="hljs-keyword">const</span> helloParser = C.string(<span class="hljs-string">'hello'</span>); <span class="hljs-keyword">const</span> white = C.char(<span class="hljs-string">' '</span>); <span class="hljs-keyword">const</span> worldParser = C.char(<span class="hljs-string">'world'</span>); <span class="hljs-keyword">const</span> combinator = helloParser.then(white.rep()).then(worldParser);</code></pre> <h2 id="floor-notation">Floor notation</h2> <pre><code class="language-js"><span class="hljs-comment">// N: Number Bundle, C: Chars Bundle</span> <span class="hljs-keyword">const</span> {Streams, N, C}= <span class="hljs-built_in">require</span>(<span class="hljs-string">'@masala/parser'</span>); <span class="hljs-keyword">const</span> stream = Stream.ofString(<span class="hljs-string">'|4.6|'</span>); <span class="hljs-keyword">const</span> floorCombinator = C.char(<span class="hljs-string">'|'</span>).drop() .then(N.number()) <span class="hljs-comment">// we have ['|', 4.6], we drop '|'</span> .then(C.char(<span class="hljs-string">'|'</span>).drop()) <span class="hljs-comment">// we have [4.6, '|'], we keep [4.6]</span> .single() <span class="hljs-comment">// we had [4.6], now just 4.6</span> .map(<span class="hljs-function"><span class="hljs-params">x</span> =&gt;</span><span class="hljs-built_in">Math</span>.floor(x)); <span class="hljs-comment">// The parser parses a stream of characters</span> <span class="hljs-keyword">const</span> parsing = floorCombinator.parse(stream); assertEquals( <span class="hljs-number">4</span>, parsing.value, <span class="hljs-string">'Floor parsing'</span>);</code></pre> <h2 id="explanations">Explanations</h2> <p>According to Wikipedia <em>&quot;in functional programming, a parser combinator is a higher-order function that accepts several parsers as input and returns a new parser as its output.&quot;</em></p> <h2 id="the-parser">The Parser</h2> <p>Let&#39;s say we have a document :</p> <blockquote> <blockquote> <blockquote> <p>The James Bond series, by writer Ian Fleming, focuses on a fictional British Secret Service agent created in 1953, who featured him in twelve novels and two short-story collections. Since Fleming&#39;s death in 1964, eight other authors have written authorised Bond novels or novelizations: Kingsley Amis, Christopher Wood, John Gardner, Raymond Benson, Sebastian Faulks, Jeffery Deaver, William Boyd and Anthony Horowitz.</p> </blockquote> </blockquote> </blockquote> <p>The parser could fetch every names, ie two consecutive words starting with uppercase. The parser will read through the document and aggregate a Response, which contains a value and the current offset in the text.</p> <p>This value will evolve when the parser will meet new characters, but also with some function calls, such as the <code>map()</code> function.</p> <p><img src="./documentation/parsec-monoid.png" alt=""></p> <h2 id="the-response">The Response</h2> <p>By definition, a Parser takes text as an input, and the Response is a structure that represents your problem. After parsing, there are two subtypes of <code>Response</code>:</p> <ul> <li><code>Accept</code> when it found something. </li> <li><code>Reject</code> if it could not.</li> </ul> <pre><code class="language-js"> <span class="hljs-keyword">let</span> response = C.char(<span class="hljs-string">'a'</span>).rep().parse(Streams.ofString(<span class="hljs-string">'aaaa'</span>)); assertEquals(response.value.join(<span class="hljs-string">''</span>), <span class="hljs-string">'aaaa'</span> ); assertEquals(response.offset, <span class="hljs-number">4</span> ); assertTrue(response.isAccepted()); assertTrue(response.isConsumed()); <span class="hljs-comment">// Partially accepted</span> response = C.char(<span class="hljs-string">'a'</span>).rep().parse(Streams.ofString(<span class="hljs-string">'aabb'</span>)); assertEquals(response.value.join(<span class="hljs-string">''</span>), <span class="hljs-string">'aa'</span> ); assertEquals(response.offset, <span class="hljs-number">2</span> ); assertTrue(response.isAccepted()); assertFalse(response.isConsumed()); </code></pre> <h2 id="building-the-parser-and-execution">Building the Parser, and execution</h2> <p>Like a language, the parser is built then executed. With Masala, we build using other parsers.</p> <pre><code class="language-js"><span class="hljs-keyword">const</span> helloParser = C.string(<span class="hljs-string">'hello'</span>); <span class="hljs-keyword">const</span> white = C.char(<span class="hljs-string">' '</span>); <span class="hljs-keyword">const</span> worldParser = C.char(<span class="hljs-string">'world'</span>); <span class="hljs-keyword">const</span> combinator = helloParser.then(white.rep()).then(worldParser);</code></pre> <p>There is a compiling time when you combine your parser, and an execution time when the parser runs its <code>parse(stream)</code> function. You will have the <code>Response</code> after parsing. </p> <p>So after building, the parser is executed against a stream of token. For simplicity, we will use a stream of characters, which is a text :)</p> <h2 id="hello-gandhi">Hello Gandhi</h2> <p>The goal is check that we have Hello &#39;someone&#39;, then to grab that name</p> <pre><code class="language-js"><span class="hljs-comment">// Plain old javascript</span> <span class="hljs-keyword">const</span> {Streams, C}= <span class="hljs-built_in">require</span>(<span class="hljs-string">'@masala/parser'</span>); <span class="hljs-keyword">var</span> helloParser = C.string(<span class="hljs-string">"Hello"</span>) .then(C.char(<span class="hljs-string">' '</span>).rep()) .then(C.letters()) <span class="hljs-comment">// succession of A-Za-z letters</span> .last(); <span class="hljs-comment">// keeping previous letters</span> <span class="hljs-keyword">var</span> value = helloParser.val(<span class="hljs-string">"Hello Gandhi"</span>); <span class="hljs-comment">// val(x) is a shortcut for parse(Stream.ofString(x)).value;</span> assertEquals(<span class="hljs-string">'Gandhi'</span>, value);</code></pre> <h1 id="parser-combinations">Parser Combinations</h1> <p>Let&#39;s use a real example. We combine many functions that returns a new Parser. And each new Parser is a combination of Parsers given by the standard bundles or previous functions.</p> <pre><code class="language-js"><span class="hljs-keyword">import</span> {Streams, N,C, F} <span class="hljs-keyword">from</span> <span class="hljs-string">'@masala/parser'</span>; <span class="hljs-keyword">const</span> blanks = <span class="hljs-function"><span class="hljs-params">()</span>=&gt;</span>C.char(<span class="hljs-string">' '</span>).optrep(); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">operator</span>(<span class="hljs-params">symbol</span>) </span>{ <span class="hljs-keyword">return</span> blanks().drop() .then(C.char(symbol)) <span class="hljs-comment">// '+' or '*'</span> .then(blanks().drop()) .single(); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> N.integer() .then(operator(<span class="hljs-string">'+'</span>).drop()) .then(N.integer()) <span class="hljs-comment">// then(x) creates a tuple - here, one value was dropped</span> .map(<span class="hljs-function"><span class="hljs-params">tuple</span> =&gt;</span> tuple.at(<span class="hljs-number">0</span>) + tuple.at(<span class="hljs-number">1</span>)); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multiplication</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> N.integer() .then(operator(<span class="hljs-string">'*'</span>).drop()) .then(N.integer()) .array() <span class="hljs-comment">// we can have access to the value of the tuple</span> .map( <span class="hljs-function">(<span class="hljs-params">[left,right]</span>)=&gt;</span> left * right); <span class="hljs-comment">// more modern js </span> } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scalar</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> N.integer(); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">combinator</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> F.try(sum()) .or(F.try(multiplication())) <span class="hljs-comment">// or() will often work with try()</span> .or(scalar()); } <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseOperation</span>(<span class="hljs-params">line</span>) </span>{ <span class="hljs-keyword">return</span> combinator().parse(Streams.ofString(line)); } assertEquals(<span class="hljs-number">4</span>, parseOperation(<span class="hljs-string">'2 +2'</span>).value, <span class="hljs-string">'sum: '</span>); assertEquals(<span class="hljs-number">6</span>, parseOperation(<span class="hljs-string">'2 * 3'</span>).value, <span class="hljs-string">'multiplication: '</span>); assertEquals(<span class="hljs-number">8</span>, parseOperation(<span class="hljs-string">'8'</span>).value, <span class="hljs-string">'scalar: '</span>);</code></pre> <p>A curry paste is an higher order ingredient made from a good combination of spices.</p> <p><img src="./documentation/images/curry-paste.jpg" alt=""></p> <h2 id="precedence">Precedence</h2> <p>Precedence is a technical term for priority. Using:</p> <pre><code class="language-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">combinator</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> F.try(sum()) .or(F.try(multiplication())) <span class="hljs-comment">// or() will often work with try()</span> .or(scalar()); } <span class="hljs-built_in">console</span>.info(<span class="hljs-string">'sum: '</span>,parseOperation(<span class="hljs-string">'2+2'</span>).value);</code></pre> <p>We will give priority to sum, then multiplication, then scalar. If we had put <code>scalar()</code> first, we would have first accepted <code>2</code>, then what could we do with <code>+2</code> alone ? It&#39;s not a valid sum ! Moreover <code>+2</code> and <code>-2</code> are acceptable scalars. </p> <h2 id="try-x-or-y-">try(x).or(y)</h2> <p><code>or()</code> will often be used with <code>try()</code>, that makes <a href="https://en.wikipedia.org/wiki/Backtracking">backtracking</a> : it saves the current offset, then tries an option. And as soon that it&#39;s not satisfied, it goes back to the original offset and use the parser inside the <code>.or(P)</code> expression.`.</p> <p> Like Haskell&#39;s Parsec, Masala Parser can parse infinite look-ahead grammars but performs best on predictive (LL[1]) grammars.</p> <p>Let see how with <code>try()</code>, we can look a bit ahead of next characters, then go back:</p> <pre><code> <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">F</span>.</span></span><span class="hljs-keyword">try</span>(sum<span class="hljs-literal">()</span>).<span class="hljs-keyword">or</span>(<span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">F</span>.</span></span><span class="hljs-keyword">try</span>(multiplication<span class="hljs-literal">()</span>)).<span class="hljs-keyword">or</span>(scalar<span class="hljs-literal">()</span>) <span class="hljs-comment">// try(sum()) parser in action</span> <span class="hljs-number">2</span> *<span class="hljs-number">2</span> ..ok..ok ↑oups: go back <span class="hljs-keyword">and</span> <span class="hljs-keyword">try</span> multiplication. Should be OK.</code></pre><p>Suppose we do not <code>try()</code> but use <code>or()</code> directly:</p> <pre><code> <span class="hljs-keyword">sum</span>().<span class="hljs-keyword">or</span>(multiplication()).<span class="hljs-keyword">or</span>(<span class="hljs-keyword">scalar</span>()) <span class="hljs-comment">// testing sum()</span> 2 *2 ..ok..ok ↑<span class="hljs-comment">oups: cursor is NOT going back. So now we must test</span> <span class="hljs-comment">'*2'</span> ; Is it (multiplication())? <span class="hljs-keyword">No</span> ; <span class="hljs-keyword">or</span>(<span class="hljs-keyword">scalar</span>()) ? neither</code></pre><h1 id="recursion">Recursion</h1> <p>Masala-Parser (like Parsec) is a top-down parser and doesn&#39;t like <a href="https://cs.stackexchange.com/a/9971">Left Recursion</a>.</p> <p>However, it is a resolved problem for this kind of parsers, with a lot of documentation. You can read more on <a href="./documentation/recursion.md">recursion with Masala</a>, and checkout examples on our Github repository ( <a href="https://github.com/d-plaindoux/masala-parser/blob/master/integration-npm/examples/recursion/aaab-lazy-recursion.js">simple recursion</a>, or <a href="https://github.com/d-plaindoux/masala-parser/blob/master/integration-npm/examples/operations/plus-minus.js">calculous expressions</a> ).</p> <h1 id="simple-documentation-of-core-bundles">Simple documentation of Core bundles</h1> <h2 id="core-parser-functions">Core Parser Functions</h2> <p>Here is a link for <a href="./documentation/parser-core-functions.md">Core functions documentation</a>.</p> <p>It will explain <code>then()</code>, <code>drop()</code>, <code>map()</code>, <code>rep()</code>, <code>opt()</code> and other core functions of the Parser with code examples.</p> <p>### </p> <h2 id="the-chars-bundle">The Chars Bundle</h2> <p>Example: </p> <pre><code class="language-js">C.char(<span class="hljs-string">'-'</span>) .then(C.letters()) .then(C.char(<span class="hljs-string">'-'</span>)) <span class="hljs-comment">// accepts '-hello-' ; value is ['-','hello','-']</span> <span class="hljs-comment">// reject '-hel lo-' because space is not a letter </span></code></pre> <p><a href="./documentation/chars-bundle.md">General use</a></p> <ul> <li><code>letter()</code>: accept a european letter (and moves the cursor)</li> <li><code>letters()</code>: accepts many letters and returns a string</li> <li><code>letterAs(symbol)</code>: accepts a european(default), ascii, or utf8 Letter. <a href="./documentation/chars-bundle.md">More here</a></li> <li><code>lettersAs(symbol)</code>: accepts many letters and returns a string</li> <li><code>emoji()</code>: accept any emoji sequence. <a href="https://github.com/d-plaindoux/masala-parser/issues/86">Opened Issue</a>.</li> <li><code>notChar(x)</code>: accept if next input is not <code>x</code></li> <li><code>char(x)</code>: accept if next input is <code>x</code></li> <li><code>charIn(&#39;xyz&#39;)</code>: accept if next input is <code>x</code>, <code>y</code> or <code>z</code></li> <li><code>charNotIn(&#39;xyz&#39;)</code>: accept if next input is not <code>x</code>, <code>y</code> or <code>z</code></li> <li><code>subString(length)</code>: accept any next <em>length</em> characters and returns the equivalent string</li> <li><code>string(word)</code>: accept if next input is the given <code>word</code> </li> <li><code>stringIn(words)</code>: accept if next input is the given <code>words</code> <a href="./documentation/chars-bundle.md">More here</a></li> <li><code>notString(word)</code>: accept if next input is <em>not</em> the given <code>word</code></li> <li><code>charLiteral()</code>: single quoted char element in C/Java : <code>&#39;a&#39;</code> is accepted</li> <li><code>stringLiteral()</code>: double quoted string element in java/json: <code>&quot;hello world&quot;</code> is accepted</li> <li><code>lowerCase()</code>: accept any next lower case inputs</li> <li><code>upperCase()</code>: accept any next uppercase inputs</li> </ul> <p>Other example:</p> <pre><code class="language-js">C.string(<span class="hljs-string">'Hello'</span>) .then(C.char(<span class="hljs-string">' '</span>)) .then(C.lowerCase().rep().join(<span class="hljs-string">''</span>)) <span class="hljs-comment">// accepts Hello johnny ; value is ['Hello', ' ', 'johnny']</span> <span class="hljs-comment">// rejects Hello Johnny : J is not lowercase ; no value</span></code></pre> <h2 id="the-numbers-bundle">The Numbers Bundle</h2> <ul> <li><code>number()</code>: accept any float number, such as -2.3E+24, and returns a float </li> <li><code>digit()</code>: accept any single digit, and returns a <strong>number</strong></li> <li><code>digits()</code>: accept many digits, and returns a <strong>number</strong>. Warning: it does not accept <strong>+-</strong> signs symbols.</li> <li><code>integer()</code>: accept any positive or negative integer</li> </ul> <h2 id="the-flow-bundle">The Flow Bundle</h2> <p>The flow bundle will mix ingredients together.</p> <p>For example if you have a Parser <code>p</code>, <code>F.not(p)</code> will accept anything that does not satisfy <code>p</code></p> <p>All of these functions will return a brand new Parser that you can combine with others.</p> <p>Most important:</p> <ul> <li><code>F.try(parser).or(otherParser)</code>: Try a parser and come back to <code>otherParser</code> if failed</li> <li><code>F.any()</code>: Accept any character (and so moves the cursor)</li> <li><code>F.not(parser)</code>: Accept anything that is not a parser. Often used to accept until a given <em>stop</em> </li> <li><code>F.eos()</code>: Accepted if the Parser has reached the <strong>E*<em>nd *</em>O</strong>f <strong>S</strong>tream</li> <li><code>F.moveUntil(string|stopParser)</code>: Alternative for <strong>regex</strong>. Will traverse the document <strong>until</strong> the <em>stop parser</em><ul> <li>returns <code>undefined</code> if <em>stop</em> is not found</li> <li>returns all characters if <em>stop</em> is found, and set the cursor at the spot of the stop</li> </ul> </li> <li><code>F.dropTo(string|stopParser)</code>: Will traverse the document <strong>including</strong> the <em>stop parser</em></li> </ul> <p>Others:</p> <ul> <li><code>F.lazy(parser, ?params)</code>: Makes a lazy evaluation. May be used for Left recursion (difficult)</li> <li><code>F.parse(parserFunction)</code>: Create a new Parser from a function. Usually, you won&#39;t start here.</li> <li><code>F.subStream(length)</code>: accept any next characters </li> <li><code>F.returns(value)</code>: forces a returned value</li> <li><code>F.error()</code>: returns an error. Parser will never be accepted</li> <li><code>F.satisfy(predicate)</code>: check if condition is satisfied</li> <li><code>F.startsWith(value)</code>: create a no-op parser with initial value </li> </ul> <h2 id="license">License</h2> <p>Copyright (C)2016-2019 D. Plaindoux.</p> <p>This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.</p> <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.</p> <p>You should have received a copy of the GNU Lesser General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.</p> </div> </div> <div class="col-4 col-menu menu-sticky-wrap menu-highlight"> <nav class="tsd-navigation primary"> <ul> <li class="globals "> <a href="globals.html"><em>Globals</em></a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_masala_parser_d_.html">"masala-<wbr>parser.d"</a> </li> </ul> </nav> <nav class="tsd-navigation secondary menu-sticky"> <ul class="before-current"> </ul> </nav> </div> </div> </div> <footer class="with-border-bottom"> <div class="container"> <h2>Legend</h2> <div class="tsd-legend-group"> <ul class="tsd-legend"> <li class="tsd-kind-module"><span class="tsd-kind-icon">Module</span></li> <li class="tsd-kind-object-literal"><span class="tsd-kind-icon">Object literal</span></li> <li class="tsd-kind-variable"><span class="tsd-kind-icon">Variable</span></li> <li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li> <li class="tsd-kind-function tsd-has-type-parameter"><span class="tsd-kind-icon">Function with type parameter</span></li> <li class="tsd-kind-index-signature"><span class="tsd-kind-icon">Index signature</span></li> <li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li> <li class="tsd-kind-enum-member"><span class="tsd-kind-icon">Enumeration member</span></li> <li class="tsd-kind-property tsd-parent-kind-enum"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-enum"><span class="tsd-kind-icon">Method</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li> <li class="tsd-kind-interface tsd-has-type-parameter"><span class="tsd-kind-icon">Interface with type parameter</span></li> <li class="tsd-kind-constructor tsd-parent-kind-interface"><span class="tsd-kind-icon">Constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li> <li class="tsd-kind-index-signature tsd-parent-kind-interface"><span class="tsd-kind-icon">Index signature</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li> <li class="tsd-kind-class tsd-has-type-parameter"><span class="tsd-kind-icon">Class with type parameter</span></li> <li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class"><span class="tsd-kind-icon">Accessor</span></li> <li class="tsd-kind-index-signature tsd-parent-kind-class"><span class="tsd-kind-icon">Index signature</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li> <li class="tsd-kind-call-signature tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li> </ul> </div> </div> </footer> <div class="container tsd-generator"> <p>Generated using <a href="http://typedoc.org/" target="_blank">TypeDoc</a></p> </div> <div class="overlay"></div> <script src="assets/js/main.js"></script> <script>if (location.protocol == 'file:') document.write('<script src="assets/js/search.js"><' + '/script>');</script> </body> </html>