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

selena

v0.4.3

Published

A textual language that compiles to UML sequence diagrams.

Downloads

32

Readme

Selena

CI Test Coverage Maintainability

Selena is a textual language that compiles to UML sequence diagrams. It is written in (mostly) object-oriented TypeScript.

This package contains all the fundamental logic for making the system work. This includes: a lexer (tokenizer), a parser, the sequence data structures, diagram data structures, diagram layout computation, renderer interface and renderer implementations. This package does not contain any user interface.

The design of this system is extremely flexible overall:

  • Information flows one-way: input to tokenizer, tokenizer to parser, to diagram construction, to renderer.
  • There are very few token types used in the custom-built lexer, and the parser is a recursive-descent parser that is simple to understand and reason about.
  • The horizontal and vertical layout algorithms work independently of each other and can easily be swapped out.
  • The horizontal layout algorithm is based on an abstract system of constraints that is, in my opinion, quite elegant.
  • The renderer interface is rather minimal, so that a wide range of rendering targets could be supported without changing anything about the diagram structure.

Installation and Usage

Install with NPM:

npm install selena

The installed package contains the transpiled JavaScript sources and TypeScript typings, if you need them.

How to Use

The Selena script is first compiled to a Sequence object via the exported function compileToSequence. This Sequence can then be converted into a Diagram, which can be rendered to any target. When rendering, the diagram needs to be laid out, then its size needs to be measured and the renderer prepared for that size, at which point the diagram's draw method can be called.

Currently, only one renderer is available:

  • BrowserSvgRenderer: renders into an <svg> element in a browser environment.

Example

The following code shows how to parse some input, create the diagram and render it inside a browser environment:

import { compileToSequence, Diagram, BrowserSvgRenderer } from 'selena'

const input = '(the input source code would be here)'
const sequence = compileToSequence(input)
const diagram = Diagram.create(sequence)

// the following must run in the browser
// use horizontal and vertical padding: 50 extra pixels on each side
const svgRenderer = new BrowserSvgRenderer(50, 50)
diag.layout(svgRenderer)
svgRenderer.prepare(diag.getComputedSize())
diag.draw(svgRenderer)

const element = svgRenderer.finish()
// you can now append element to the DOM

Language Guide

Every Selena script consists of an Object Definition Section followed by a Message Section. There can be many object definitions and many messages. The language includes support for comments (pieces of text not to be included in the diagram).

Object Definitions

Objects can be defined as follows:

object foo = "Foo"
object(actor) bar = "Bar"

This will create one component object with id foo and label Foo, as well as one actor object with id bar and label Bar.

The object types differ in the way they are presented: Components are drawn as boxes, while actors are drawn as stick figures.

Messages

Messages (or activations) are written as arrows. Most types of messages can have other messages as children, i.e., functions calling other functions. For an object to send a message, it has to be active. An object is active for the duration it takes to handle a message. Initially, no object is active. A found message (message from the outside) can activate an object initially. Afterwards, more messages can follow. For example:

object foo = "Foo"
object bar = "Bar"

*->foo "a found message targeting foo" {
  ->bar "a message from foo to bar"
  ->foo "a message from foo to itself"
  ->bar {
    ->foo
  }
}

*->bar
*->bar {}

The above script defines two objects foo and bar. Then there is a found message activating foo and a few nested messages on multiple levels. Note that labels are entirely optional, as are the braces ({, }) in case there are no nested messages.

Message types

There are found messages from the outside to an object, regular messages between two objects, and lost messages from an object to the outside. Lost messages are specified as in the following example:

object foo = "Foo"
object bar = "Bar"

*->foo "foo is activated" {
  ->* "this message is leaving foo"
}

Again, the label is optional. Lost messages cannot have a block (as there is no execution context).

Regular messages have different types as well. By default, they are synchronous. By specifying async, create or destroy the type of message can be changed:

object foo = "Foo"
object bar = "Bar"

*->foo {
  ->(create) bar "this message creates bar"
  ->(async) bar "this is an asynchronous message" {
    ->foo "it can contain other messages"
    ->(async) foo "they can be of any type"
  }
  ->(destroy) bar "this message destroys bar"
}

Asynchronous messages, like synchronous messages, can have children. create and destroy messages cannot. If you want to be explicit about a message's synchronicity, you can specify its type as sync, e.g., ->(sync) bar, though this is not required.

Note that create and destroy will have a special effect on object positioning inside the diagram and on the length of its lifeline.

Return values

By default, reply messages are automatically created for synchronous messages. To specify the reply message label, use a return statement:

object foo = "Foo"
object bar = "Bar"

*->foo {
  ->bar "message" {
    return "reply"
  }
}

The above will set the reply message label to read reply.

Asynchronous messages do not include a reply by default. Mostly, it makes no sense to include one, either. Instead, an explicit second asynchronous message can serve as callback. To specify a reply regardless, the same syntax can be used:

object foo = "Foo"
object bar = "Bar"

*->foo {
  ->(async) bar "async message" {
    return "with a reply"
  }
}

No other type of message (lost, found, create, destroy) may have a return statement.

Comments

Comments can be used to include notes in the Selena script that should not appear in the diagram. They can be positioned anywhere (except inside of strings) and begin with the hash symbol #. They extend to the end of the line. For example:

# this is a comment
object foo = "Foo"  # this is another comment