Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
@nicetouch/yarn-bound
Advanced tools
Yarn is a language for writing dialogue trees.
YarnBound attempts to be the simplest way to use the Yarn language in the context of a javascript application. It is a wrapper around a specific forked version of bondage.js, where effort has been made to comply with the Yarn 2.0 spec.
Quality-of-life features on top of bondage.js:
isDialogueEnd
property with the last Result in a dialogueBondage.js also does not support
Character: some text
annotation[b]Markup[/b]
because these are not language features (it's confusing). YarnBound adds these things.
The only thing I know to be missing from the spec and non-unity-specific docs (at time of Yarn 2.0's release) is the built-in wait
command, because I can't tell what I would want it to do.
Install with npm i -S yarn-bound
or grab yarn-bound.js
from the /dist/
folder.
For information on how to write Yarn, visit the official documentation. Start there! YarnBound is useful after you have a yarn dialogue written and in string format. It's worth skimming the Yarn language spec as well.
To get started with YarnBound, import and create a new instance.
import YarnBound from 'yarn-bound'
// or node:
// const bondage = require('yarn-bound')
// or in a script tag:
// <script src="path-to-file/yarn-bound.min.js"></script>
const runner = new YarnBound(options)
You can then access the first Result with:
runner.currentResult
To continue the dialogue, call advance()
.
runner.advance()
runner.currentResult // is now the next Result
If you were on an Options Result, you would call advance()
with the index of the desired option.
runner.advance(2)
runner.currentResult // is now the Result after the selected option
You can also call jump()
with the title
of a node to jump directly to that node. This allows for external control over the story flow.
That's all there is to the basic operation!
dialogue (required): string - The Yarn dialogue to run. A .yarn file in string form.
startAt: string: - The title of the node to start the dialogue on.
functions: object - An object containing custom functions to run when they are called in a yarn expression.
runner.registerFunction(key, func)
after initialization.variableStorage: object - A custom storage object with get()
and set()
functions (a new Map()
, for instance.)
handleCommand: function - If you provide this, YarnBound will advance()
right past Command Results, instead calling handleCommand()
with the Command Result as the single argument (see below for the data structure).
combineTextAndOptionsResults: boolean - If this is true, a Text Result followed by an Options Result will be combined into one Options Result with a text
property.
locale: string - Used for pluralization markdown attributes.
Results, found on runner.currentResult
, come in three flavors:
You can tell which kind it is by using instanceof
runner.currentResult instanceof YarnBound.TextResult
runner.currentResult instanceof YarnBound.OptionsResult
runner.currentResult instanceof YarnBound.CommandResult
A TextResult looks like this:
{
"text": "This is a line of text.",
"hashtags": ['someHashtag'],
"metadata": {/* see below */}
}
If it is the last Result in the dialogue, there will also be a isDialogueEnd
property with the value of true
.
An Options Result looks like this:
{
"options": [
{
"text": "Red",
"isAvailable": true,
"hashtags": []
},
{
"text": "Blue",
"isAvailable": true,
"hashtags": []
}
],
"metadata": {/* see below */}
}
If combineTextAndOptionsResults
is enabled, there could be a text
property on the Options Result. advance()
from it with an option's index as usual.
A Command Result looks like this:
{
"command": "someCommand",
"hashtags": [],
"metadata": {/* see below */}
}
It could also have a isDialogueEnd
property on it. Command Results are handled and skipped through when a handleCommand
function is supplied.
Every Result contains metadata
which includes node header tags including title
, and also any file tags.
{
"title": "StartingNode",
"someTag": "someTag",
"filetags": [
"someFiletag"
]
}
Let's start with this code:
import YarnBound from 'yarn-bound';
// empty lines and uniform leading whitespace are trimmed
// so you can write your nodes in template strings neatly.
const dialogue = `
title: WhereAreYou
---
Where are you?
-> Home
Nice.
<<doSomething home>>
-> Work
Rough.
<<doSomething work>>
That's it!
===
`
const runner = new YarnBound({
dialogue,
startAt: 'WhereAreYou'
})
When we log out runner.currentResult
above, we will get a TextResult with the text
"Where are you?"
to continue, we call
runner.advance()
and runner.currentResult
will be an OptionsResult with an options array with two objects in it. One object's text
property is "Nice" and one's is "Rough". We will choose "Nice" by calling:
runner.advance(0)
Now, runner.currentResult
is a CommandResult where command
is "doSomething home".
runner.advance()
One final TextResult, but this time isDialogueEnd
is true
.
If combineTextAndOptionsResults
was true, the first value for runner.currentResult
would be the same OptionsResult as above, but with a text
property that says "Where are you?".
If a handleCommand
function was supplied, it would be called and we would skip straight from the OptionsResult to the last TextResult.
If you are supplying a functions
object, it would look like this:
const runner = new YarnBound({
dialogue,
functions: {
someFunction: (arg) => {/* do stuff */},
someOtherFunction: (arg1, arg2) => {/* do other stuff */},
}
})
An array containing Results already visited is located at runner.history
.
A simple react component can be found at: react-dialogue-tree
When a handleCommand function is supplied, ending a dialogue with a command or set of commands can cause unexpected behavior. Any commands at the end of the dialogue will be handled upon reaching the last non-command result (usually, a command will only be handled when advancing past the previous non-command result). This is furthermore a problem when ending the dialogue with a command inside a conditional:
The lookahead feature won't handle commands or set variables, so a dialogue like this will behave inconsistently:
<<set $a = false>>
Hello
<<set $a = true>>
<<some command>>
<<if $a == true>>
Goodbye
<<endif>>
When processing the "Hello" TextResult, the lookahead feature will detect the end of the dialogue because it will see if $a == true
evaluate to false, since it hasn't.
Thinking that the dialogue is over, it will try to handle any trailing commands, actually doing the variable setting and this time reaching the if $a == true
block.
YarnBound will correct itself and not include the isDialogueEnd
flag prematurely, but any side effects performed by setting the variable and handling the command will have already happened. This can cause bugs!
It is suggested to avoid this pattern. But if you must use it, or prevent lookahead for any other reason, there is a special <<pause>>
command you can use:
<<set $a = false>>
Hello
<<set $a = true>>
<<some command>>
<<pause>>
<<if $a == true>>
Goodbye
<<endif>>
Note that you will have to call advance() again after reaching the pause command. Even if you have supplied a handleCommand function, runner.currentResult
will be a CommandResult, with a command of "pause".
Also note, however, that a "pause" command at the end of a dialogue will never have the isDialogueEnd
flag, as lookahead is disabled.
A minified version exists at yarn-bound/dist/yarn-bound.min.js
.
If you want to transpile for yourself, use import YarnBound from 'yarn-bound/src/index'
and make sure your transpiler isn't ignoring it. You will also need to transpile @mnbroatch/bondage
, and include both in your bundle, if necessary.
A version compatibile with internet explorer is at yarn-bound/dist/yarn-bound.ie.js
.
FAQs
Quality of life wrapper around bondage.js
The npm package @nicetouch/yarn-bound receives a total of 14 weekly downloads. As such, @nicetouch/yarn-bound popularity was classified as not popular.
We found that @nicetouch/yarn-bound demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.