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

@mnbroatch/bondage

v4.2.4

Published

Yarn parser for Javascript

Downloads

183

Readme

The changes in this fork have been merged into a branch of the original bondage.js project.

This project is a runner for Yarn dialogues, attempting compliance with the 2.0 language specification.

API improvements and additional features are present in YarnBound, which uses this package under the hood.

Known Deviations from Yarn 2.0 spec

  • Reading from a .yarn file is left to the user; dialogues should be supplied to bondage.js as a text string or array of node objects.
  • Some minutia about what unicode characters define a string has not been considered.

There are features in the Yarn docs that are not present in the Yarn language spec. Known examples are:

  • Character: some text annotation
  • [b]Markup[/b]

These exist in YarnBound but not here.

Usage

Install with npm i -S bondage or grab bondage.js from the /dist/ folder.

For information on how to write Yarn, visit the official documentation.

The examples below illustrate how bondage.js in particular works:

Basic Dialogue

import bondage from 'bondage';
// or node: 
// const bondage = require('bondage')
// or in a script tag:
// <script src="path-to-file/bondage.min.js"></script>
 
// bondage.js strips empty lines, but make sure lines have
// no leading whitespace (besides indentation)!
const dialogue = ` 
# someFiletag
title: StartingNode
someTag: someTag
---
This is a line of text.#someHashtag
This is another line of text.
===
`

const runner = new bondage.Runner()
runner.load(dialogue)
const generator = runner.run('StartingNode')
let node = generator.next().value
console.log('node', node)

When we log out node above, we will see this object structure:

{
  "text": "This is a line of text.",
  "hashtags": ['someHashtag'],
  "metadata": {
    "title": "StartingNode",
    "someTag": "someTag",
    "filetags": [
      "someFiletag"
    ]
  }
}

Notice that hashtags at the end of a line go in a hashtags array.

to continue, we call

node = generator.next().value

again, and if we log the new node, we see:

{
  "text": "This is another line of text.",
  "hashtags": [],
  "metadata": {
    "title": "StartingNode",
    "someTag": "someTag",
    "filetags": [
      "someFiletag"
    ]
  }
}

If we had jumped, we would see the new node's title and header tags under the metadata property (along with the same fileTags).

Options

Given this dialogue:

# someFiletag
title: StartingNode
someTag: someTag
---
What color do you like?
-> Red
  You picked Red!
-> Blue
  You picked Blue!
===

We can start the dialogue runner like above.

const runner = new bondage.Runner()
runner.load(dialogue)
const generator = runner.run('StartingNode')
let node = generator.next().value

which will give us a text result like the last example. However, the next node we get from calling generator.next().value will be:

{
  "options": [
    {
      "text": "Red",
      "isAvailable": true,
      "hashtags": []
    },
    {
      "text": "Blue",
      "isAvailable": true,
      "hashtags": []
    }
  ],
  "metadata": {
    "title": "StartingNode",
    "someTag": "someTag",
    "filetags": [
      "someFiletag"
    ]
  }
}

In order to continue the dialogue, you will need to call

node.select(0);
node = generator.next().value

in order to move to the line with text, "You picked Red!"

But how will your view layer know whether you're looking at a text result or an options result? Use instanceof:

node instanceof bondage.TextResult

node instanceof bondage.OptionsResult

node instanceof bondage.CommandResult

Speaking of CommandResult...

Commands

The third and last result type you need to know about is CommandResult. Given this dialogue:

# someFiletag
title: StartingNode
someTag: someTag
---
Sending a command...
<<someCommand with spaces>>
===

You will see a "Sending a command..." TextResult, but the next node will look like this:

{
  "name": "someCommand with spaces",
  "hashtags": [],
  "metadata": {
    "title": "StartingNode",
    "someTag": "someTag",
    "filetags": [
      "someFiletag"
    ]
  }
}

Your program can do what it wants with that, then call generator.next().value to get the next node, as usual.

Custom Variable Storage

Bondage keeps track of variables internally. Optionally, you can supply your own variableStorage. variableStorage is an object with get() and set() methods defined.

const customStorage = new Map()
customStorage.set('hello', 1)

const runner = new bondage.Runner()
runner.setVariableStorage(customStorage)
runner.load(dialogue)

Call setVariableStorage BEFORE loading a dialogue with runner.load. This is because declare commands will resolve when the dialogue loads (as opposed to when runner.run() is called)

Above, we set an initial value for the hello variable, so if a line of dialogue contains {$hello}, it will show the number 1, no need to call <<set $hello = 1>>.

Simple dialogues can probably just use the built-in storage.

Functions

You can also register functions to be used in your dialogue.

runner.registerFunction('sayHello', () => 'hello')

If a line of dialogue contains {sayHello()}, it will show hello.

Object Input Format

In addition to the regular yarn format as a string, bondage also accepts a javascript object. This is an intermediary format exported by some utilities. The text format is nicer to work with, so it should be preferred. For reference,

#someFiletag
#someOtherFiletag
title: SomeNode
tags: hello
arbitraryKey: arbitraryValue
---
This is a line of text
<<jump SomeOtherNode>>
===

title: SomeOtherNode
---
This is another line of text.
===

is equivalent to:

[
  {
    "title": "SomeNode",
    "tags": "hello",
    "arbitraryKey": "arbitraryValue",
    "body": "This is a line of text\n<<jump SomeOtherNode>>\n",
    "filetags": [
      "someFiletag",
      "someOtherFiletag"
    ]
  },
  {
    "title": "SomeOtherNode",
    "body": "This is another line of text.\n",
    "filetags": [
      "someFiletag",
      "someOtherFiletag"
    ]
  }
]

Other included versions

A minified version exists at bondage/dist/bondage.min.js.

If you want to transpile for yourself, use import bondage from 'bondage/src/index' and make sure it's being included by your build system.

If you need compatibility with internet explorer, you can transpile for yourself or use bondage/dist/bondage.ie.js.

Development

The parser is compiled ahead of time, so after making changes to the grammar you will need to run node src/parser/make-parser. This is done automatically during npm run build.