npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mobdata/mobdsl

v1.0.0

Published

Parser tool that produces configuration for Apache CouchDb's replication. Uses a simple, straight-forward DSL.

Downloads

2

Readme

mobdsl

Parser tool that produces configuration for Apache CouchDb's replication. Uses a simple, straight-forward DSL.

Install

npm install @mobdata/mobdsl

Why

Apache CouchDb's replication documents can be awkward to manage if there are large numbers of servers and/or if they have filters. This DSL can specify in a few lines what would otherwise require hundreds/thousands of lines of JSON and JavaScript.

Examples

To quickly see what mobdsl is doing run this:

npm run install --save-dev
cd examples
cat rule.txt
./generate_single.js

From the above you will see how a single rule, easily readable, is converted into a combination of JSON and JavaScript, ready for CouchDb's purposes.

generate_multiple.js shows two lines of rules (from rules.txt) being converted into much longer JSON.

view_filter.js extracts the dense JavaScript function from the output and formats it for easier reading.

How-to

The DSL is a parser that accepts replication rules and server configurations and returns a JSON array of replication documents that can be applied to an Apache CouchDb's _replicator database. It's most easily used as part of the MobNode webapp.

Rules

The simplest rule might be:

send "my_data" to "remote_node"

Which follows the format:

send "<database_name>" to "<remote_server>"

Save time and typing using nicknames and lists

Rules are separated by commas. Servers have nicknames called "node_names" (see "opts" below). Multiple nodes can be grouped into lists.

friends = ["thor", "hulk", "cap"],
enemies = ["thanos", "ultron", "hela"],
frenemies: ["loki", "deadpool"],
send "secret_plans" to friends,
send "misdirection_plans" to enemies,
send "bad_jokes" to frenemies

No JavaScript required using if-clauses

Rules can include complex logic. mobdsl converts it into JavaScript and JSON be applies it to CouchDb.

friends = ["thor", "hulk", "cap"],
enemies = ["thanos", "ultron", "hela"],
frenemies: ["loki", "deadpool"],
send "upcoming_schedule" to friends if package-meta:designation is "secret",
send "upcoming_schedule" to enemies if package-meta:designation is "public",
send "upcoming_schedule" to frenemies if package-meta.designation is "public",
send "jokes" to friends if package-meta:rating is "funny",
send "jokes" to enemies if package-meta:rating is "sarcastic",
send "jokes" to frenemies if package-meta:rating is "sarcastic" or package-meta:rating is "annoying"

The rules can inspect:

  • Each document being sent, called the "package",
  • Each document's metadata, called "package-meta",
  • Each server sending documents, called the "source", and
  • Each server receiving documents, called the "target".

The source and target attributes are defined the opts data described further down. The package is a JSON document. It's the document you or your user is storing to a CouchDb database.

The contents of package are defined solely by your user. If you need to inspect the document in order to know if it can be replicated to another server you'll then need to know its basic structure/contents. This will require some coordination with whomever is writing the document to CouchDb.

The contents of package-meta will include whatever data helps describe the document but is not part of that document. For example, if a database contains articles from various magazines, the package might be each article's text, including title and author(s). The package-meta might then be some JSON describing things like number of words in the article, overall size of the package, source magazine, etc. In a security company, package-meta might contain the security designation of the document, such as "designation": "secret" or "designation": "confidential".

JSON examples of what package and package-meta look like are given further below.

Operators

The if-clauses can compare data in the following ways.

| Operator | Definition | Example | | --------- |------------------------------| ---------| | is | Relative equality, == | package:title is "A title" | | isnot | Not equal, !== | package-meta:type isnot "press release" | | isin | Is in a list/array | package:author isin ["Stephen King", "Clive Barker", "Bram Stoker"] | | notin | Is not in a list/array | package:author notin ["Nora Roberts", "Julia Quinn", "Sarah MacLean"] | | lte | Less than or equal | package-meta:size lte 50 | | lt | Less than | package-meta:size lt 51 | | gte | Greater than or equal | package-meta:priority gte 9 | | gt | Greater than | package-meta:priorty gt 5 | | matches | Matches a JavaScript regex | package:title matches /PRESS RELEASE.*/ | | mst | "More Secure Than", compares government classifications | target:classification mst package-meta:classification |

Opts

The following defines the opts data structure. To be clear, mobdsl has always been part of a larger whole. The MobNode webapp uses mobdsl and provides the opts data, which can be non-trivial.

opts contains the server information for your enterprise. Each server is called a node. This means that the rules you write will define how data is replicated between these nodes. Each node has its own set of rules: node "A" has rules for sending data to nodes "B" and "C", and node "B" has its own rules for sending to nodes "A" and "C" and so on. On each node we refer to itself as the "source" node or "base" node.

The opts structure looks like this:

{
  "nodes": {
    "<node_name>": {
      "node_name": "<node_name>",
      "url": "<url>",
      "attributes": { "<attribute>": "<value>", "<attribute>": "<value>", ... }
    },
    ...
  },
  "_source_node_name": "<node_name>"
}

nodes is a list of all the servers that are part of the replication system. Each server, or node, has a node_name to refer to it. _source_node_name is the node_name of the current server.

The attributes for each node define what can queried in a given rule. send "data" to all_servers where target:company is "my_company" is only a valid rule if company is one of the attributes for the nodes.

const opts =
{
  "nodes": {
    "base": {
      "node_name": "base",
      "url": "https://test.server.com:443",
      "attributes": { "company": "apple", "office_type": "regional" }
    },
    "node_a": {
      "node_name": "node_a",
      "url": "https://test1.server.com:443",
      "attributes": { "company": "google", "office_type": "regional" }
    },
    "node_b": {
      "node_name": "node_b",
      "url": "https://test2.server.com:443",
      "attributes": { "company": "google", "office_type": "hq" }
    },
    "node_c": {
      "node_name": "node_c",
      "url": "https://test3.server.com:443",
      "attributes": { "company": "google", "office_type": "regional" }
    }
  },
  "_source_node_name": "base"
}

Two side notes:

  • You'll notice there's a duplication of the node_name, for example
    • 'node_a': { 'node_name': 'node_a', ... }
    • Why specify "node_a" twice? For now it's a requirement, but in the future we'll fix it so that this duplication isn't needed.
  • Each node_name is a nickname for your servers and is the primary way a user references the server in the rules.
    • Keep the node names as short and identifiable as possible, because users will be writing them a lot and will be reading them a lot.

From JavaScript to JSON

Assuming you had the rules and opts available, your next step is to convert it into JSON, before storing it in CouchDb.

import parser from 'mobdsl'

const rules = '<some cool replication rules>'
const opts = '<JSON doc describing the servers you are replicating between>'
const replicationDocs = parser.parse(rules, opts)
console.log(replicationDocs)

The above would output something like this:

{
    "rules": [{
            "db": "internal_research",
            "target": "https://md-104.trinityalps.org:443",
            "hash": "3f1694b10fe80e58",
            "continuous": true,
            "filter": "base_to_remote_node_a_filter : function(doc,req) {/* lengthy js code here */}"
        },
        {
            "db": "personnel_evaluations",
            "target": "https://md-103.trinityalps.org:443",
            "hash": "14471863c449a66c",
            "continuous": true,
            "filter": "base_to_remote_node_b_filter : function(doc,req) {/* lengthy js code here */}"
        }
    ]
}

This JSON can then be inserted, with a couple changes, into a CouchDb server's _replicator database, which would then trigger CouchDb's replication processes.

Developing mobdsl

mobdsl is written using PEG.js's excellent parser generator. By editing mobdata_grammar.pegjs and running npm run build the PEG.js generator will generate the necessary JavaScript files that make up the module.

The grammar, in turn, makes use of some pure JavaScript functions found in the lib directory. These are written in ES6 and babel will down-convert to ES5.

When the module is published the ES6 source code files and mobdata_grammar.pegjs file are ignored.