diffusion
Version:
Diffusion JavaScript client
362 lines (359 loc) • 11.2 kB
JavaScript
var parser = require('topics/topic-selector-parser');
/**
* Create {@link TopicSelector} instances for use with other API methods.
* <p />
* <br />
* Selectors are evaluated against topic paths. A topic path is a '/'
* separated string of parts, which map to the topic hierarchy. Each part is
* formed of one or more UTF characters, except '/'. Topic paths are absolute,
* and evaluated from the root of the current domain.
*
* @example
* // Create a topic selector
* var selector = diffusion.selectors.parse('?foo/bar/.*');
*
* @namespace diffusion.selectors
*/
var topicSelectors = {
/**
* Parse an expression to create a selector.
*
* This function can take any number of arguments. Each argument can be a string
* or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument.
*
* <p>
* The following types of expression are supported. The type is determined
* by the first character of the expression.
* </p>
*
* <dl>
* <dt>Path
* <dd>Path expressions begin with the character <code>></code>. The remainder of
* the expression must be a valid topic path. A topic path is a '/'
* separated string of parts. Each part is formed of one or more UTF
* characters, except '/'.
* <p>
* A {@link TopicSelector.Type#PATH PATH} selector is returned that only
* selects the topic with the given path.
* </p>
* <h4>Abbreviated Path Expressions</h4>
* <p>
* In Diffusion 5.2, an alternative syntax for path expressions was added.
* An <em>abbreviated path expression</em> is any valid topic path (see
* above) that begins with a character other than one of <code>#</code>,
* <code>?</code>, <code>></code>, <code>*</code>, <code>$</code>,
* <code>%</code>, <code>&</code>, or <code><</code>.
* This syntax allows most topic paths to be used directly as selector
* expressions which appears more natural.
*
* <p>
* This method converts abbreviated path expressions to standard path
* expressions by prepending the <code>></code> character. Thus <code>a/b</code> is
* interpreted as <code>>a/b</code>.
* <p>
* <code>parse("a/b").expression</code> will return <code>">a/b"</code>.
*
* <dt>Split-path pattern
* <dd>Split-path pattern expressions begin with the character <code>?</code>.
* The remainder of the expression is split into a list of regular
* expressions using the <code>/</code> character as a separator.
*
* <p>
* A {@link TopicSelector.Type.SPLIT_PATH_PATTERN SPLIT_PATH_PATTERN}
* selector is returned that selects topics for which each regular
* expression matches each part of the topic path at the corresponding
* level.
* </p>
*
* <dt>Full-path pattern
* <dd>Full-path pattern expressions begin with the character <code>*</code>. The
* remainder of the pattern is a regular expression.
*
* <p>
* A {@link TopicSelector.Type.FULL_PATH_PATTERN FULL_PATH_PATTERN} selector
* is returned that selects topics for which the regular expression matches
* the complete topic path.
* </p>
*
* <p>
* Full-path patterns provide a lot of expressive power but should be used
* sparingly since the server can evaluate split-path patterns more
* efficiently.
*
* <p>
* Selector sets are the preferred way to combine expressions.
* <code>parse("a", "b")</code> is equivalent to the full-path expression "
* <code>*[a|b]</code>", but can be evaluated more efficiently by the
* server.
*
* <dt>Selector set
* <dd>Selector set expressions begin with the character <code>#</code>. The
* remainder of the expression is a list of contained selectors, formatted
* as described below.
*
* <p>
* A {@link TopicSelector.Type.SELECTOR_SET SELECTOR_SET} selector is
* returned that selects topics that match any of the contained selectors.
* </p>
*
* <p>
* The contained
* selectors are formatted as follows. First, any selector sets are expanded
* to produce a full list of non-selector set expressions. Then the selector
* expressions are concatenated, separated by the separator <code>////</code>.
* This separator has been chosen as it is not valid in a path, and is not a
* useful sequence in a pattern.
* </p>
*
* </dl>
*
* <h2>Descendant pattern qualifiers</h2>
*
* <p>
* Split-path and full-path pattern expressions can be further modified by
* appending <code>/</code> or <code>//</code>. These control the behaviour of the
* selector with respect to the descendants of the topics that match the
* pattern.
*
* <ul>
*
* <li>
* If the expression does not end with <code>/</code> or <code>//</code>, it selects
* only the topics that match the pattern.</li>
*
* <li>
* If the expression ends with <code>/</code>, it selects only the descendants of
* the matching topics, excluding the matching topics.</li>
*
* <li>
* If the expression ends with <code>//</code>, it selects the matching topics
* and all of their descendants.</li>
* </ul>
* </p>
*
* <h2>Regular expressions</h2>
*
* <p>
* Any {@link Pattern Java-style regular expression} can be used in
* split-path and full-path patterns, with the following restrictions:
*
* <ul>
* <li>A regular expression may not be empty.
* <li>A regular expression used in split-path patterns may not contain the
* path separator <code>/</code>.
* <li>A regular expression used in full-path patterns may not contain the
* selector set separator <code>////</code>.
* </ul>
*
* <p>
* Regular expressions that break any of these restrictions would never
* match a topic path, so they make no practical difference.
* </p>
*
*
* <h2>Examples</h2>
*
* <h3>Path expressions</h3>
* <table>
* <tr>
* <th></th>
* <th>Matches <code>alpha/beta</code>?</th>
* <th>Matches <code>alpha/beta/gamma</code>?</th>
* </tr>
*
* <tr>
* <td><code>>alpha/beta</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>>alpha/beta/gamma</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>>beta</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>>.*</code><code>/.*</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>>/alpha/beta/</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* </table>
*
* <h3>Abbreviated path expressions</h3>
* <table>
* <tr>
* <th></th>
* <th>Matches <code>alpha/beta</code>?</th>
* <th>Matches <code>alpha/beta/gamma</code>?</th>
* </tr>
*
* <tr>
* <td><code>alpha/beta</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>alpha/beta/gamma</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>beta</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>/alpha/beta/</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* </table>
*
* <h3>Split-path pattern expressions</h3>
* <table>
* <tr>
* <th></th>
* <th>Matches <code>alpha/beta</code>?</th>
* <th>Matches <code>alpha/beta/gamma</code>?</th>
* </tr>
*
* <tr>
* <td><code>?alpha/beta</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>?alpha/beta/gamma</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>?beta</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>?.*</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>?.*</code><code>/.*</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>?alpha/beta/</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>?alpha/beta//</code></td>
* <td align="center">yes</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>?alpha/.*</code><code>//</code></td>
* <td align="center">yes</td>
* <td align="center">yes</td>
* </tr>
*
* </table>
*
* <h3>Full-path pattern expressions</h3>
* <table>
* <tr>
* <th></th>
* <th>Matches <code>alpha/beta</code>?</th>
* <th>Matches <code>alpha/beta/gamma</code>?</th>
* </tr>
*
* <tr>
* <td><code>*alpha/beta</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>*alpha/beta/gamma</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>*beta</code></td>
* <td align="center">no</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>*.*beta</code></td>
* <td align="center">yes</td>
* <td align="center">no</td>
* </tr>
*
* <tr>
* <td><code>*.*</code></td>
* <td align="center">yes</td>
* <td align="center">yes</td>
* </tr>
*
*
* <tr>
* <td><code>*alpha/beta/</code></td>
* <td align="center">no</td>
* <td align="center">yes</td>
* </tr>
*
* <tr>
* <td><code>*alpha/beta//</code></td>
* <td align="center">yes</td>
* <td align="center">yes</td>
* </tr>
* </table>
*
* @example
* // Simple selector
* var selector = diffusion.selectors.parse(">a/b");
*
*
* @example
* // Creating a selector set
* var selectorSet = diffusion.selectors.parse(">a", ">b");
*
* @param {...String | TopicSelector | String[] }
* expression - The pattern expression(s).
* @return {TopicSelector} The topic selector. If multiple expressions are provided,
* this will return a <code>SELECTOR_SET</code> that will match if any of the
* provided <code>selectors</code> match.
* @function diffusion.selectors#parse
*/
parse: parser
};
module.exports = topicSelectors;